Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should I write function parameters to enforce a move rather than a copy?

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)) { }

...?

like image 359
Adrian Avatar asked Jan 08 '14 19:01

Adrian


People also ask

Why is move faster than copy C++?

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.

Is it better to pass by reference or value C++?

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.

What does move function do in C++?

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.

Why is it better to pass by reference?

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.


1 Answers

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.

like image 191
Kerrek SB Avatar answered Oct 16 '22 19:10

Kerrek SB