Std::vector копирование объектов с помощью push_back?

После большого количества исследований с valgrind я сделал вывод, что std::vector создает копию объекта, который вы хотите push_back.

Это правда? Вектор не может содержать ссылку или указатель объекта без копии?!

Спасибо

Ответ 1

Да, std::vector<T>::push_back() создает копию аргумента и сохраняет его в векторе. Если вы хотите сохранить указатели на объекты в своем векторе, создайте std::vector<whatever*> вместо std::vector<whatever>.

Однако вам нужно убедиться, что объекты, на которые ссылаются указатели, остаются в силе, пока вектор содержит ссылку на них (интеллектуальные указатели, использующие идиому RAII, решают проблему).

Ответ 2

Да, std::vector хранит копии. Как vector знать, каковы ожидаемые сроки жизни ваших объектов?

Если вы хотите передать или передать права собственности на объекты, используйте указатели, возможно, умные указатели, такие как shared_ptr (найдены в Boost или TR1), чтобы облегчить управление ресурсами.

Ответ 3

std::vector всегда делает копию того, что хранится в векторе.

Если вы сохраняете вектор указателей, то он сделает копию указателя, но не экземпляр, на который указывает указатель. Если вы имеете дело с большими объектами, вы можете (и, вероятно, должны) всегда использовать вектор указателей. Часто использование вектора интеллектуальных указателей соответствующего типа хорош для целей безопасности, так как обработка жизни объекта и управление памятью могут быть сложными в противном случае.

Ответ 4

Начиная с С++ 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.

Ответ 5

Не только std::vector делает копию того, что вы отталкиваете назад, но определение коллекции утверждает, что оно будет делать это, и что вы не можете использовать объекты без правильной семантики копии в векторе. Так, например, вы не используете auto_ptr в векторе.

Ответ 6

Релевантно в С++ 11 является семейство функций-членов emplace, которое позволяет передавать права собственности на объекты, перемещая их в контейнеры.

Идиома использования будет выглядеть как

std::vector<Object> objs;

Object l_value_obj { /* initialize */ };
// use object here...

objs.emplace_back(std::move(l_value_obj));

Перемещение для объекта lvalue важно, поскольку в противном случае оно будет перенаправлено в качестве ссылки или ссылки на константу, и конструктор перемещения не будет вызываться.

Ответ 7

если вы не хотите копировать; то лучшим способом является использование вектора указателя (или другой структуры, которая служит для одной и той же цели). если вы хотите получить копии; используйте прямо push_back(). у вас нет другого выбора.

Ответ 8

Почему для этого выяснилось, что нужно провести много исследований? Просто подтвердите это с помощью простого кода, например.

std::vector<std::string> vec;

{
      std::string obj("hello world");
      vec.push_pack(obj);
}

std::cout << vec[0] << std::endl;  

Если напечатан символ "hello world", объект должен быть скопирован