0

I wrote the class below and I have a question about it. The function sayHello() returns an object which is going to be destroyed after that line. However, it doesn't use move constructor. Isn't it an rvalue reference? Why it doesn't use move constructor?

class FString {
private:
    char *ptr;
public:
    FString() : ptr(nullptr) {}

    FString(const char *str) {
        cout << "Called: FString(const char *str)\n";
        //...
    }

    ~FString() {
        cout << "Called: ~FString()\n";
        //...
    }

    FString(FString &&s) {
        cout << "Called: FString(FString &&s)\n";
        //...
    }
};


FString sayHello() {
    FString s("Hello World!");
    return s;
}

int main() {
    FString s("Hello World!");
    FString s2(sayHello());
    return 0;
}

Output:

Called: FString(const char *str)
Called: FString(const char *str)
Called: ~FString()
Called: ~FString()

Thanks.

g3d
  • 63
  • 7

2 Answers2

1

The move is elided; that's an optimisation allowed in various situations, even if (as here) the move constructor has side effects, so that omitting the call changes the program's behaviour.

Specifically, when the program uses a temporary (or a local variable, when returning from a function) to directly initialise an object of the same type, that move can be omitted by using the same storage for both objects. This happens here, both when using the s within sayHello to initialise the return value, and when using that value to initialise s2, so no move or copy constructor is needed.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
0

The compiler optimizes away the need for a move constructor. Have you tried disabling optimization and checking whether the result is the same?

Tommy Andersen
  • 7,165
  • 1
  • 31
  • 50