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.