Я пытаюсь заставить своих коллег использовать больше алгоритмов и менее явных циклов. Итак, у моего коллеги есть вектор shared_ptr
s, и он делает копию этого vector
и элементов, на которые он указывает. У него что-то вроде этого:
dst.clear();
for (size_t i=0; i<src.size(); i++)
{
std::shared_ptr<Type> pObject(new Type(*src[i]));
dst.push_back(pObject);
}
Я думаю, что это можно было бы лучше сделать, используя std::copy
с std::back_inserter
, но я не вижу, как заставить его копировать элементы, на которые указывают, используя материал, который в настоящее время находится в STL.
Мог бы свернуть свой собственный, но подумал бы, что эта проблема возникла бы достаточно, чтобы ее уже решили.
@WhozCraig, во-первых, в этом коде мне многое не нравится. Во-вторых, почему получение подлинных копий — это совершенно другая проблема? Вот является проблема, которую я хочу решить. Извините, вы правы, я пропустил *src[i]
, исправил.
Подлинные копии становятся проблемой, когда в вашей коллекции могут быть экземпляры DerivedOne
и DerivedTwo
, на которые ссылаются два std::shared_ptr<SomeBase>
, где SomeBase
— полиморфная основа обоих производных. Теперь сделайте подлинную копию обоих, используя только то, что у вас есть: два std::shared_ptr<SomeBase>
. эм... да. Ты видишь проблему ? Как упомянул Барри, метод clone()
— ваш выход. Короче говоря, универсальной серебряной пули здесь нет.
Это хороший способ написать Java с помощью компилятора C++. Подлинным решением STL (он же Алекс Степанов) будет избавление от вектора указателей, но оно требует гораздо большего контекста проблемы, которую пытается решить ваш код. По сути, то, что я говорю, это проблема XY.
Я понимаю твою точку зрения @WhozCraig. Однако в этом случае используются только объекты одного типа, так что это нормально. Никакой нарезки не произойдет.
@IvanAksamentov-Drop, да, мне это не очень нравится, но, к сожалению, IIRC, это требование к типу базового объекта. Не допускается перемещение в памяти или это может вызвать проблемы.
Если ему не разрешено перемещаться в памяти, вы можете использовать std::deque<Type>
. Копирование deque
скопирует все элементы.
std::transform(src.begin(), src.end(),
std::back_inserter(dst),
[](shared_ptr<Type> const& ptr) {
return make_shared<Type>(*ptr);
});
С оговоркой, что если Type
является полиморфным, это, вероятно, делает неправильную вещь, и вы захотите добавить метод clone()
или что-то в этом роде.
В C++20 это будет выглядеть примерно так:
dst = src | ranges::view::transform([](shared_ptr<Type> const& ptr){
return make_shared<Type>(*ptr);
})
| ranges::to<std::vector>;
Которые вы уже можете получить с range-v3 сегодня.
Обратите внимание, что если Type
является полиморфным, код в исходном вопросе также работает неправильно.
Хотя Type
полиморфен, в данном случае они все еще одного типа, так что все в порядке.
Я думаю, что это именно то, что мне нужно. Спасибо.
Во-первых, я бы использовал
std::make_shared
. Во-вторых, если основной причиной использования общих указателей в первую очередь является полиморфизм, и вам нужны подлинные копии производных экземпляров, вам нужно решить совершенно другую проблему. Если вам просто нужен еще один вектор общих указателей такой же, еще одна другая проблема (но тривиальная). А для кода это я не вижуsrc
, используемого где-либо в фактической копии (хотя его величина подозрительно участвует в ограничении циклов), поэтому опубликованный код не имеет никакого смысла.