Является ли std:: векторное копирование объектов с помощью push back?


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

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

спасибо

8 134

8 ответов:

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

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

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

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

начиная с C++11, все стандартные контейнеры (std::vector,std::map и т. д.) поддержка семантики перемещения, что означает, что теперь вы можете передавать значения rvalues в стандартные контейнеры и избегать копирования:

// 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::shared_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 всегда делает копию того, что хранится в векторе.

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

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

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

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

std::vector<Object> objs;

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

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

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

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

почему потребовалось много исследований valgrind, чтобы узнать это! Просто докажите это себе с помощью простого кода, например

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

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

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

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