Copies! Copies everywhere! And dynamic allocations too!
So was the world before C++11. In these old days, if we had to pass a large object to a function that needed its own instance of it, then we would have certainly created a copy of it.
struct catalog { catalog(const std::vector<item>& entries) // Here we have one allocaction, for the storage, // plus copies of the elements from the vector. : m_entries(entries) {} private: std::vector<item> m_entries; }; void create_catalog(int n) { // One allocation of n items, plus their initialization. std::vector<item> entries(n); // ... catalog c(entries); // I don’t need the entries anymore, but they are still here. }
<utility>
C++11 introduces the move semantics and the std::move() function. In practice it means far fewer copies, as the instances’ data is transfered from one place to another.
struct catalog { // Note the pass-by-value for the argument. catalog(std::vector<item> entries) // Explicit transfer into m_entries, no allocation. : m_entries(std::move(entries)) {} private: std::vector<item> m_entries; }; void create_catalog(int n) { // The single allocation in this program. std::vector<item> entries(n); // ... // I don’t need the entries anymore, so I transfer them. catalog c(std::move(entries)); }
In the example above, there is only one allocation, for the vector of entries in create_catalog(), and zero copies. The ownership of the allocated space is actually transfered from one vector to another every time std::move() is used, until it ends up in m_entries.