I want to move a large container from a return value into another class using that class' constructor. How do I formulate the parameter to ensure that it doesn't end up being copied?
/* for the sake of simplicity, imagine this typedef to be global */
typedef std::unordered_map<std::string, unsigned int> umap;
umap foo()
{
umap m; /* fill with lots of data */
return m;
}
class Bar
{
public:
Bar(umap m) : bm(m) { }
private:
umap bm;
};
Bar myBar(foo()); // run foo and pass return value directly to Bar constructor
Will above formulation trigger the appropriate behavior, or do I need to specify the constructor's parameters as rvalue-references, the way containers do for their own move-semantics?
public:
Bar(umap&& m) : bm(m) { }
or
public:
Bar(umap&& m) : bm(std::move(m)) { }
...?
It's faster because moving allows the source to be left in a invalid state, so you can steal it's resources. For example, if a object holds a pointer to a large block of allocated memory, a move can simply steal the pointer while a copy must allocate its own memory and copy the whole memory block.
As a rule passing by const reference is better. But if you need to modify you function argument locally you should better use passing by value. For some basic types the performance in general the same both for passing by value and by reference.
Move Constructor And Semantics: std::move() is a function used to convert an lvalue reference into the rvalue reference. Used to move the resources from a source object i.e. for efficient transfer of resources from one object to another. std::move() is defined in the <utility> header.
Pass-by-references is more efficient than pass-by-value, because it does not copy the arguments. The formal parameter is an alias for the argument.
If you want to support moving and copying, the easiest way would be to pass by value:
Bar(umap m) : bm(std::move(m)) { }
Now you can construct Bar
from both an lvalue and an rvalue:
umap m;
Bar b1(m); // copies
Bar b2(std::move(m)); // moves
Bar b3(make_umap()); // moves
If you only want to support rvalues, then use an explicit rvalue reference:
Bar(umap && m) : bm(std::move(m)) { }
The std::move
is always necessary, since (m)
is always an lvalue.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With