После большого количества исследований с valgrind я сделал вывод, что std::vector создает копию объекта, который вы хотите push_back.
Это правда? Вектор не может содержать ссылку или указатель объекта без копии?!
Спасибо
После большого количества исследований с valgrind я сделал вывод, что std::vector создает копию объекта, который вы хотите push_back.
Это правда? Вектор не может содержать ссылку или указатель объекта без копии?!
Спасибо
Да, std::vector<T>::push_back()
создает копию аргумента и сохраняет его в векторе. Если вы хотите сохранить указатели на объекты в своем векторе, создайте std::vector<whatever*>
вместо std::vector<whatever>
.
Однако вам нужно убедиться, что объекты, на которые ссылаются указатели, остаются в силе, пока вектор содержит ссылку на них (интеллектуальные указатели, использующие идиому RAII, решают проблему).
Да, std::vector
хранит копии. Как vector
знать, каковы ожидаемые сроки жизни ваших объектов?
Если вы хотите передать или передать права собственности на объекты, используйте указатели, возможно, умные указатели, такие как shared_ptr
(найдены в Boost или TR1), чтобы облегчить управление ресурсами.
std::vector всегда делает копию того, что хранится в векторе.
Если вы сохраняете вектор указателей, то он сделает копию указателя, но не экземпляр, на который указывает указатель. Если вы имеете дело с большими объектами, вы можете (и, вероятно, должны) всегда использовать вектор указателей. Часто использование вектора интеллектуальных указателей соответствующего типа хорош для целей безопасности, так как обработка жизни объекта и управление памятью могут быть сложными в противном случае.
Начиная с С++ 11, все стандартные контейнеры (std::vector
, std::map
и т.д.) поддерживают семантику перемещения, что означает, что теперь вы можете передавать значения r стандартным контейнерам и избегать копирования:
// Example object class.
class object
{
private:
int m_val1;
std::string m_val2;
public:
// Constructor for object class.
object(int val1, std::string &&val2) :
m_val1(val1),
m_val2(std::move(val2))
{
}
};
std::vector<object> myList;
// #1 Copy into the vector.
object foo1(1, "foo");
myList.push_back(foo1);
// #2 Move into the vector (no copy).
object foo2(1024, "bar");
myList.push_back(std::move(foo2));
// #3 Move temporary into vector (no copy).
myList.push_back(object(453, "baz"));
// #4 Create instance of object directly inside the vector (no copy, no move).
myList.emplace_back(453, "qux");
В качестве альтернативы вы можете использовать различные интеллектуальные указатели, чтобы получить в основном тот же эффект:
std::unique_ptr
пример
std::vector<std::unique_ptr<object>> myPtrList;
// #5a unique_ptr can only ever be moved.
auto pFoo = std::make_unique<object>(1, "foo");
myPtrList.push_back(std::move(pFoo));
// #5b unique_ptr can only ever be moved.
myPtrList.push_back(std::make_unique<object>(1, "foo"));
std::shared_ptr
пример
std::vector<std::unique_ptr<object>> objectPtrList2;
// #6 shared_ptr can be used to retain a copy of the pointer and update both the vector
// value and the local copy simultaneously.
auto pFooShared = std::make_shared<object>(1, "foo");
objectPtrList2.push_back(pFooShared);
// Pointer to object stored in the vector, but pFooShared is still valid.
Не только std::vector делает копию того, что вы отталкиваете назад, но определение коллекции утверждает, что оно будет делать это, и что вы не можете использовать объекты без правильной семантики копии в векторе. Так, например, вы не используете auto_ptr в векторе.
Релевантно в С++ 11 является семейство функций-членов emplace
, которое позволяет передавать права собственности на объекты, перемещая их в контейнеры.
Идиома использования будет выглядеть как
std::vector<Object> objs;
Object l_value_obj { /* initialize */ };
// use object here...
objs.emplace_back(std::move(l_value_obj));
Перемещение для объекта lvalue важно, поскольку в противном случае оно будет перенаправлено в качестве ссылки или ссылки на константу, и конструктор перемещения не будет вызываться.
если вы не хотите копировать; то лучшим способом является использование вектора указателя (или другой структуры, которая служит для одной и той же цели). если вы хотите получить копии; используйте прямо push_back(). у вас нет другого выбора.
Почему для этого выяснилось, что нужно провести много исследований? Просто подтвердите это с помощью простого кода, например.
std::vector<std::string> vec;
{
std::string obj("hello world");
vec.push_pack(obj);
}
std::cout << vec[0] << std::endl;
Если напечатан символ "hello world", объект должен быть скопирован