Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does deleting the move constructor cause a compile error?

Tags:

c++

gcc

The following code works OK:

#include <iostream>
using namespace std;
struct oops
{
        ~oops()
        {
                cout << " oops! " << endl;
        }
};

struct sample
{
        oops* x = nullptr;
        sample(oops* p) : x(p)
        {
                cout << "sample: " << p << endl;
        }
        ~sample()
        {
                delete x;
                cout << "destroy sample " << endl;
        }
        sample(const sample&)
        {
                cout << "copy sample " << endl;
        }
        sample(sample&&)
        {
                cout << "move sample " << endl;
        }
};

int main()
{
        sample s = new oops;
        return 0;
}

Result:

sample: 0x1470c20
 oops!
destroy sample

It clearly shows that neither the move nor copy constructor was called. When these constructors are deleted,

sample(const sample&) = delete;
sample(sample&&) = delete;

gcc gives a compile error:

bpp.cpp: In function ‘int main()’:
bpp.cpp:29:17: error: use of deleted function ‘sample::sample(sample&&)’
  sample s = new oops;
                 ^
bpp.cpp:24:2: note: declared here
  sample(sample&&) = delete;
  ^
bpp.cpp:14:2: note:   after user-defined conversion: sample::sample(oops*)
  sample(oops* p) : x(p)
  ^

Does this have anything to do with -fno-elide-constructors? How can I compile it without defining these constructors or using an explicit constructor?

Edit: My GCC verison is 5.4.0. The command is:

g++ bpp.cpp -std=c++17
like image 337
Lizho Avatar asked May 10 '19 05:05

Lizho


People also ask

Does compiler generate move constructor?

With C++11, the compiler generates 2 new functions related to move semantics: a move constructor X(X&& other) , that calls a move constructor of each class member and base class, a move assignment operator X& operator=(X&& other) , that calls a move assignment operator on each class member and base class.

What does implicit move constructor do?

Implicitly-defined move constructor For non-union class types (class and struct), the move constructor performs full member-wise move of the object's bases and non-static members, in their initialization order, using direct initialization with an xvalue argument.

What is the difference between a move constructor and a copy constructor?

If any constructor is being called, it means a new object is being created in memory. So, the only difference between a copy constructor and a move constructor is whether the source object that is passed to the constructor will have its member fields copied or moved into the new object.


1 Answers

sample s = new oops;

This is a form of copy initialization. For a compiler to resolve it until C++17, a copy or move constructor must exist. However, a compiler is free to elide its call due to optimizations (with GCC and -fno-elide-constructors, the move constructor is called).

Since C++17, neither of these constructors is required: https://wandbox.org/permlink/3V8glnpqF5QxljJl.


How can I compile it without defining these constructors or using explicit constructor?

Very simply, avoid copy initialization and use direct initialization instead:

sample s { new oops };

Or, use C++17.

like image 87
Daniel Langr Avatar answered Oct 10 '22 00:10

Daniel Langr