C++ Move Constructor – Why It Is Not Called

c++c++11

Why is nothing being printed in this example? I'm compiling in Clang on Coliru.

#include <iostream>

struct S
{
    S()    noexcept = default;
    S(S&&) noexcept { std::cout << "move-ctor"; }
};

void f(S) {}

int main()
{
    f(S{});
}

Best Answer

The compiler is performing copy elision, which is allowed per paragraph 12.8/31 of the C++11 Standard even if your move constructor, copy constructor, or destructor have side effects:

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the constructor selected for the copy/move operation and/or the destructor for the object have side effects.

The term copy elision is used even when a move is being elided:

This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

[...]

— when a temporary class object that has not been bound to a reference (12.2) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

[...]

With GCC, you can use the -fno-elide-constructors to inhibit copy elision. In this case, you would see that the move constructor gets invoked, as in this live example.

Related Question