Consider the following code snippet:
#include <iostream>
#include <string>
class A {
public:
A() {
std::cout << "A::A()\n";
}
~A() {
std::cout << "A::~A()\n";
}
A(const A&) = delete;
A(A&&) {
std::cout << "A::A(A&&)\n";
};
};
A f() {
A a;
return a;
}
int main() {
A a = f();
return 0;
}
It compiles fine with g++
and clang++
and output is
A::A()
A::~A()
It seems like RVO kicks in in that case. Note that no move constructor is being called.
However, if one will remove that non-used move constructor from the code above and snippet turns into this:
#include <iostream>
#include <string>
class A {
public:
A() {
std::cout << "A::A()\n";
}
~A() {
std::cout << "A::~A()\n";
}
A(const A&) = delete;
};
A f() {
A a;
return a;
}
int main() {
A a = f();
return 0;
}
Both clang++
and g++
refuse to compile this because of copy-constructor of class A
is marked as deleted, so it seems that no RVO takes place.
How removing non-used move constructor could lead to this?
Note that in copy elision optimization, the copy/move constructor still has to be present and accessible. And it's not guaranteed that copy elision will be performed in each case.
(emphasis mine)
Even when copy elision takes place and the copy-/move-constructor is not called, it must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed.
For your code, the copy constructor has been delete
ed, and if you remove the definition of move constructor, and it won't be implicitly declared because class A
has a user-defined destructor, then both of move/copy constructor are not present and accessible, that's why compile failed.
In summary, the copy/move syntax is needed here and compiler will check for it. Then compiler will decide to perform copy elision or not (e.g. in debug mode).
BTW: You can use -fno-elide-constructors
with clang and gcc to prohibit it.