Is std::vector copying the objects with a push_back?
After a lot of investigations with v开发者_开发问答algrind, I've made the conclusion that std::vector makes a copy of an object you want to 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. If you want to store pointers to objects in your vector, create a std::vector<whatever*>
instead of 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).
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:
// 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::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::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.
Yes, std::vector
stores copies. How should vector
know what the expected life-times of your objects are?
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.
std::vector always makes a copy of whatever is being stored in the 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. So, for example, you do not use auto_ptr in a vector.
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(). you dont have any other choice.
Relevant in C++11 is the emplace
family of member functions, which allow you to transfer ownership of objects by moving them into containers.
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.
Why did it take a lot of valgrind investigation to find this out! Just prove it to yourself with some simple code e.g.
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
精彩评论