0

I am trying to test RVO and rvalue reference. Here is the code:

#include <iostream>

using namespace std;

class B{
public:
    int i;

    B(){
        i = 0;
        cout << "B() " << i << endl;
    }

    B(const B& b){
        i = 1;
        cout << "B(const B&) " << i << endl;
    }

    B(const B&& b){//if remove this constructor, then call B(const B& b)
        i = 2;
        cout << "B(const B&&) " << i << endl;
    }

    ~B(){
        cout << "~B() " << i << endl;
    }
};

B f(){
    B b;
    return b;
}

int main(){

    B b = f();

    return 0;
}

The output is:

B() 0
B(const B&&) 2
~B() 0
~B() 2

Environment: WIN8, Visual Studio 2012 Express

This means that the move constructor: B(const B&&) is called. Two issues raised:

  • Why RVO is not applied here?
  • Why NOT call the copy constructor: B(const B&)?
  • If I remove the B(const B&&), then B(const B&) is called. Weird output:

    B() 0
    B(const B&) 1
    ~B() 0
    ~B() 1

Here are references I found:


EDIT:
The move constructor should be B(B&&). The thing is why move constructor is called NOT the copy constructor.

Community
  • 1
  • 1
Zachary
  • 1,633
  • 2
  • 22
  • 34
  • 3
    Move constuctors take a non-const rvalue reference. – Vaughn Cato Jun 25 '13 at 02:41
  • Are you compiling a debug build (it looks like it)? Try the release build. – Jesse Good Jun 25 '13 at 02:43
  • @VaughnCato From the c++ standard 12.8/3: A **non-template constructor** for class X is a **move constructor** if its first parameter is of type X&&, const X&&, volatile X&&, or const volatile X&&, and either there are no other parameters or else all other parameters have default arguments – Zachary Jun 25 '13 at 02:45
  • @Zack right, but what's the point in taking a const rvalue reference? You'd end up doing the exact same thing as in the copy constructor. – mfontanini Jun 25 '13 at 02:47
  • @mfontanini Even if I remove the **const** from the two constructors, the result is the same. I think **const** is NOT the cause. – Zachary Jun 25 '13 at 02:50

1 Answers1

5

Why RVO is not applied here?

It's not simply performing optimizations. g++ does use RVO here when using -O2. You should enable optimizations on your compiler to test this out. However, note that even if RVO might be applied by some compilers, it's not mandatory, so you might see different results using different compilers.

Why NOT call the move constructor: B(const B&)?

That is a copy constructor. It's calling the move constructor which is a better match here.

If I remove the B(const B&&), then B(const B&) is called. Weird!

No, it's not weird. The move constructor will not be implicitly defined by the compiler if you define a copy constructor. Therefore, the compiler is picking the copy constructor, since no move constructor is available.

Note that your move constructor should take a non const rvalue reference:

B(B&& b) {
    // ...
}

Otherwise, you'd just end up doing the same as in the copy constructor.

mfontanini
  • 21,410
  • 4
  • 65
  • 73
  • I am using Visual Studio 2012 NOT g++. Why a move constructor is better matched? – Zachary Jun 25 '13 at 02:48
  • Some posts says even the optimization is disabled, the Visual Studio apply RVO as well. – Zachary Jun 25 '13 at 02:52
  • 1
    @Zack well it looks like it's not doing so. Did you try using optimizations? – mfontanini Jun 25 '13 at 02:57
  • 3
    @Zack: It even says so in the [docs](http://msdn.microsoft.com/en-us/library/8f8h5cxt.aspx): `/O1 and /O2 also enable the Named Return Value optimization`. – Jesse Good Jun 25 '13 at 03:01
  • I am in running the default Debug mode. If I switch to the release version. It will apply the RVO. No copy/move constructor will be called. – Zachary Jun 25 '13 at 03:04
  • @JesseGood Thx. My previous comment is not right. When I tried the release version (/O2 enabled), the result is RVO applied. – Zachary Jun 25 '13 at 03:06
  • mfontanini Could you explain more on "Otherwise, you'd just end up doing the same as in the copy constructor."? I am thinking that: since I add the const in move constructor, then both constructor means accepts a const object, so rvalue reference is better matched. Is that right? – Zachary Jun 25 '13 at 03:11
  • @Zack yes, but the whole point of the move constructor is to move the resources held by the move constructor's parameter into the one being constructed. If the parameter is `const` then you can't modify it, which disables *moving* the resources. You can at most copy them. – mfontanini Jun 25 '13 at 03:19
  • mfontanini Many thx. One left thing. If an object resources are moved to another object. Then how about the destruction of the moved object? Does it mean the moved oject need no destruction? – Zachary Jun 25 '13 at 03:24
  • @Zack the moved object's destructor will always be called. Therefore, you need to leave the moved object in a valid state. Just read about move constructors online, there will be plenty of examples. – mfontanini Jun 25 '13 at 03:35