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::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.
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
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.
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.
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.
Source: Stackoverflow.com