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
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With