Artur Pyszczuk
Artur Pyszczuk

Reputation: 1930

Pass by rvalue reference and return using std::move()?

Consider:

struct Foo {
    Foo ()                      { std::cout << "default ctor" << std::endl; }
    Foo (const Foo&)            { std::cout << "copy ctor" << std::endl; }
    Foo& operator= (const Foo&) { std::cout << "copy op" << std::endl; return *this; }
    Foo (Foo&&)                 { std::cout << "move ctor" << std::endl; }
    Foo& operator= (Foo&&)      { std::cout << "move op" << std::endl; return *this; }
    ~Foo ()                     { std::cout << "dtor" <<  std::endl; }
};


Foo process1 (Foo&& foo) {
    return foo;
}


Foo process2 (Foo&& foo) {
    return std::move (foo);
}

and usage:

Foo foo {};
foo = process1 (std::move (foo));

gives result:

default ctor
copy ctor
move op
dtor
dtor

and usage:

Foo foo {};
foo = process2 (std::move (foo));

gives result:

default ctor
move ctor
move op
dtor
dtor

Which one is preferred one (process1 or process2)?

Does it mean that in the first example (process1) if I pass object by rvalue reference to the function, which returns an Object, the copy will be made if I do not use std::move() ?

Compiler: GCC 5.2.1

Upvotes: 2

Views: 171

Answers (1)

Ami Tavory
Ami Tavory

Reputation: 76297

In the first version

Foo process1 (Foo&& foo) {
    return foo;
}

you pass it as an rvalue reference, but by the "if it has a name" heuristic, it is treated as an lvalue within the function, hence the copy ctor.

The second version "remakes" this an rvalue using std::move (which is exactly what it is meant for). Thus the copy ctor is avoided.

It's pretty reasonable to expect that a move will not be more expensive than a copy, so, given a real-life situation boiling down to this, you might prefer the second version.

Upvotes: 6

Related Questions