0

So, I have the following class:

class Foo {
public:
    Bar &&bar() {
        return std::move(_bar);
    }
private:
    Bar _bar;
}

I know that it is valid to use this class in the following context:

Bar bar;
{
    Foo foo;
    bar = foo.bar(); // bar is move-assigned, as foo is still in scope
}

Now, the situation I an wondering about is: what happens if I directly return bar from a method, without storing it beforehand:

Bar testFunc() {
    Foo foo;
    return foo.bar();
}

Bar test = testFunc();
// is test now valid?

I think that this should be theoretically fine, as testFunc returns a value that is constructed from the rvalue before foo is destroyed - but is this still the case if the compiler applies return-value-optimization?

I guess I am a little confused how exactly this works...

Felix
  • 6,885
  • 1
  • 29
  • 54

1 Answers1

1

is test now valid?

The code should be valid as long as the moved-from object is not accessed.

but is this still the case if the compiler applies return-value-optimization?

Bar testFunc() {
    Foo foo;          // Bar is constructed here
    return foo.bar(); // prvalue is move-constructed and copy elided
}
Bar test = testFunc(); // default ctor + move ctor (one copy elision)

In total one copy elision is performed.

Moving out a member seems like a code smell. It is hard to judge without knowing the concrete usage, but maybe:

Bar make_bar(const Foo& foo) {
    Bar bar;
    // init bar as needed
    return bar;
}

This way both calls will result in RVOs.

AMA
  • 4,114
  • 18
  • 32
  • Okay, after reading on value categories in c++17 - changing the method to `Bar Foo::bar()` would return a prvalue and make the optimization possible? Or does the return statement in that method (which currently returns an xvalue) have to return a prvalue as well? – Felix Jun 05 '18 at 11:42
  • @Felix, I updated the answer. I was wrong: `testFunc()` will do RVO. – AMA Jun 05 '18 at 13:03