Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RVO and deleted move constructor in C++14

I have been learning about (N)RVO for a last few days. As I read on cppreference in the copy elision article, for C++14 :

... the compilers are permitted, but not required to omit the copy- and move- (since C++11)construction of class objects even if the copy/move (since C++11) constructor and the destructor have observable side-effects. This is an optimization: even when it takes place and the copy-/move-constructor is not called, it still must be present and accessible (as if no optimization happened at all), otherwise the program is ill-formed.

So, either copy or move constructor must be present and accessible. But in the code bellow:

#include <iostream>

class myClass
{
public:
    myClass() { std::cout << "Constructor" << std::endl; }
    ~myClass() { std::cout << "Destructor" << std::endl; }

    myClass(myClass const&) { std::cout << "COPY constructor" << std::endl;}
    myClass(myClass &&) = delete;
};

myClass foo()
{
    return myClass{};
}

int main()
{
    myClass m = foo();
    return 0;
}

I got the following error: test.cpp: In function 'myClass foo()': test.cpp:15:17: error: use of deleted function 'myClass::myClass(myClass&&)' return myClass{};. I get this error even if I don't call foo() from the main(). The same issue with NRVO.

Hence the move constructor is always required, isn't it? (while the copy is not, I checked it)

I do not understand where compiler needs a move constructor. My only guess is that it might be required for constructing a temporary variable, but it sounds doubtful. Do someone knows an answer?

About the compiler: I tried it on g++ and VS compilers, you can check it online: http://rextester.com/HFT30137.

P.S. I know that in C++17 standard the RVO is obligated. But the NRVO isn't, so I want to study out what is going on here to understand when I can use NRVO.

like image 682
Annie Avatar asked Feb 03 '18 19:02

Annie


1 Answers

Cited from cppreference:

Deleted functions

If, instead of a function body, the special syntax = delete ; is used, the function is defined as deleted.

...

If the function is overloaded, overload resolution takes place first, and the program is only ill-formed if the deleted function was selected.

It's not the same thing if you explicitly define the move constructor to be deleted. Here because of the presence of this deleted move constructor, although the copy constructor can match, the move constructor is better, thus the move constructor is selected during overload resolution.

If you remove the explicit delete, then the copy constructor will be selected and your program will compile.

like image 123
llllllllll Avatar answered Oct 18 '22 06:10

llllllllll