简体   繁体   English

std :: vector是否使用push_back复制对象?

[英]Is std::vector copying the objects with a push_back?

After a lot of investigations with valgrind, I've made the conclusion that std::vector makes a copy of an object you want to push_back. 经过对valgrind的大量调查后,我得出结论,std :: vector制作了你想要push_back的对象的副本。

Is that really true ? 这是真的吗? A vector cannot keep a reference or a pointer of an object without a copy ?! 没有副本,向量不能保留对象的引用或指针?

Thanks 谢谢

Yes, std::vector<T>::push_back() creates a copy of the argument and stores it in the vector. 是的, std::vector<T>::push_back()创建参数的副本并将其存储在向量中。 If you want to store pointers to objects in your vector, create a std::vector<whatever*> instead of std::vector<whatever> . 如果要存储指向向量中对象的指针,请创建一个std::vector<whatever*>而不是std::vector<whatever>

However, you need to make sure that the objects referenced by the pointers remain valid while the vector holds a reference to them (smart pointers utilizing the RAII idiom solve the problem). 但是,您需要确保指针引用的对象保持有效,而向量包含对它们的引用(使用RAII习惯用法的智能指针解决问题)。

Yes, std::vector stores copies. 是的, std::vector存储副本。 How should vector know what the expected life-times of your objects are? vector应该如何知道物体的预期寿命是多少?

If you want to transfer or share ownership of the objects use pointers, possibly smart pointers like shared_ptr (found in Boost or TR1 ) to ease resource management. 如果要传输或共享对象的所有权,请使用指针,可能是智能指针,如shared_ptr (在BoostTR1中找到),以简化资源管理。

From C++11 onwards, all the standard containers ( std::vector , std::map , etc) support move semantics, meaning that you can now pass rvalues to standard containers and avoid a copy: 从C ++ 11开始,所有标准容器( std::vectorstd::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");

Alternatively you can use various smart pointers to get mostly the same effect: 或者,您可以使用各种智能指针来获得大致相同的效果:

std::unique_ptr example 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 example 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 always makes a copy of whatever is being stored in the vector. std :: vector总是复制存储在向量中的任何内容。

If you are keeping a vector of pointers, then it will make a copy of the pointer, but not the instance being to which the pointer is pointing. 如果你保留一个指针向量,那么它将复制指针,但不是指针所指向的实例。 If you are dealing with large objects, you can (and probably should) always use a vector of pointers. 如果您正在处理大型对象,则可以(并且可能应该)始终使用指针向量。 Often, using a vector of smart pointers of an appropriate type is good for safety purposes, since handling object lifetime and memory management can be tricky otherwise. 通常,使用适当类型的智能指针向量有利于安全目的,因为处理对象的生命周期和内存管理可能会很棘手。

Not only does std::vector make a copy of whatever you're pushing back, but the definition of the collection states that it will do so, and that you may not use objects without the correct copy semantics within a vector. std :: vector不仅会复制你正在推回的任何内容,而且集合的定义表明它会这样做,并且你可能不会在向量中没有正确的复制语义的情况下使用对象。 So, for example, you do not use auto_ptr in a vector. 因此,例如,您不在向量中使用auto_ptr。

Relevant in C++11 is the emplace family of member functions, which allow you to transfer ownership of objects by moving them into containers. C ++ 11中的相关内容是成员函数的emplace系列,它允许您通过将对象移动到容器中来转移对象的所有权。

The idiom of usage would look like 使用的习语看起来像

std::vector<Object> objs;

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

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

The move for the lvalue object is important as otherwise it would be forwarded as a reference or const reference and the move constructor would not be called. lvalue对象的移动很重要,否则它将作为引用或const引用转发,并且不会调用移动构造函数。

if you want not the copies; 如果你不想要副本; then the best way is to use a pointer vector(or another structure that serves for the same goal). 那么最好的方法是使用指针向量(或用于同一目标的其他结构)。 if you want the copies; 如果你想要副本; use directly push_back(). 直接使用push_back()。 you dont have any other choice. 你别无选择。

Why did it take a lot of valgrind investigation to find this out! 为什么需要进行大量的valgrind调查才能找到答案! Just prove it to yourself with some simple code eg 只需用一些简单的代码向自己证明,例如

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

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

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

If "hello world" is printed, the object must have been copied 如果打印“hello world”,则必须复制该对象

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM