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
.
Is that really true? A vector cannot keep a reference or a pointer of an object without a copy?
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
.
Is that really true? A vector cannot keep a reference or a pointer of an object without a copy?
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).
push_back
will perform a move instead of a copy if the argument is an rvalue reference. (Objects can be converted to rvalue references with std::move()
.) –
Bottle emplace_back
to avoid any copy or move (construct object in place provided by the container). –
Retardment void push_back( const T& value )
but actually it is still taking a copy? This is really confusing –
Upcoming void push_back( T&& value )
, can avoid making the copy (by moving the parameter). –
Bottle 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.
std::make_unique
is (annoyingly) available only in C++14 and above. Make sure you tell your compiler to set its standard conformance accordingly if you want to compile these examples. –
Predicable auto pFoo =
to avoid repetition; and all of the std::string
casts can be removed (there is implicit conversion from string literals to std::string
) –
Ancy make_unique
can easily be implemented in C++11, so it's only a slight annoyance for someone stuck with a C++11 compiler –
Ancy template<typename T, typename... Args> unique_ptr<T> make_unique(Args&&... args) { return unique_ptr<T>{new T{args...}}; }
–
Predicable std::string
and auto
usage. I've updated my answer. –
Aleksandrovsk emplace_back
a std::shared_ptr
into a std::vector
, do the raw pointer before and after the emplace point to the same memory location? –
Orestes std::move()
with std::shared_ptr
, the original shared pointer might have it's pointer changed since ownership was passed to the vector. See here: coliru.stacked-crooked.com/a/99d4f04f05e5c7f3 –
Aleksandrovsk std::shared_ptr
of several Derived classes and emplace_back
them into a std::vector
that holds std::shared_ptr
s of the Base; do I have same underlying memory? Or does it change due to casting? –
Orestes std::shared_ptr<derived>
to the vector holding std::shared_ptr<base>
and the pointer would remain the same :). –
Aleksandrovsk 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.
boost::ptr_vector
? –
Granite class Foo { typedef boost::shared_ptr<Foo> ptr; };
to just write Foo::ptr
. –
Yacano ptr_vector
for quite a while and I've never felt the need for shared ownership –
Granite shared_ptr
is not exactly fire and forget. See stackoverflow.com/questions/327573 and stackoverflow.com/questions/701456 –
Weikert 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.
emplace_back
shouldn't be used with an existing object, but to construct a new one in place –
Palatable 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
© 2022 - 2024 — McMap. All rights reserved.
*
or&
to make a pointer or reference. – Weikertpush_back
: it takes aconst&
. Either it throws the value away (useless), or there's a retrieval method. So we look at the signature ofback
, and it returns plain&
, so either the original value was copied or theconst
has been silently cast away (very bad: potentially undefined behaviour). So assuming the designers ofvector
were rational (vector<bool>
not withstanding) we conclude it makes copies. – Weikert