The source question is from Usage of this* in make_unique
The code is below, and the best answer says:
In
clone()
,*this
is an lvalue-reference toA
, so you are constructing aA
from an (lvalue-reference to)A
(insidestd::make_unique
), so you are using the implicitly declared copy-constructor ofA
:A(A const&);
I am confused that class A
has a virtual destructor virtual ~A(){}
, the compiler will not generate a copy constructor any more. So why std::make_unique<A>(*this)
could call a implicitly declared copy-constructor of A
?
class Base {
public:
virtual ~Base() {}
virtual std::unique_ptr<Base> clone() = 0;
virtual void print() = 0;
};
class A: public Base {
std::string name_;
public:
A(std::string name ){name_ = name;};
std::unique_ptr<Base> clone() override{
return std::make_unique<A>(*this);
};
void print( ) override{
std::cout << "Class A: " << name_;
};
virtual ~A(){};
};
class Factory{
std::unique_ptr<A> type = std::make_unique<A>("MyName");
public:
std::unique_ptr<Base> createInstance(){
return type->clone();
}
};
int main(){
Factory factory;
auto instance = factory.createInstance();
instance->print();
}
We all know the rule that a C++ class defines destructor function, the compiler will not generate default copy constructor and overloaded assignment operator, and the moving version for the two, look at the definition in class A
, it defines virtual ~A(){}
, so there will not a implicit copy constructor to be called for std::make_unique<A>(*this)
.
We all know the rule that a c++ class defines destructor function, the compiler will not generate default copy constructor and overloaded assignment operator,
That's not correct. The compiler declares and defines the implicit copy operations regardless of the user-declared destructor.
However this behavior has been deprecated since C++11. Still, it is not removed from the language (and I do not expect it to be removed any time soon). So at best you can expect the compiler to warn you about the deprecated behavior (for example Clang does with -Wdeprecated
), but it still has to compile the program with the implicit copy operations, for now. (Of course you could make e.g. the -Wdeprecated
warning an error with -Werror=deprecated
in Clang and other compilers may have similar options.)
That's also why following the rule-of-0/3/5 is so important. The compiler will still generate the copy operations implicitly even if they are likely to not behave correctly for a type with user-declared destructor. So you should either define the copy (and move) operations manually or define them as deleted (if copying should be impossible) when you have a user-declared destructor.