c++constructorlanguage-lawyerrule-of-three

What's with the copy-constructor if the class contains a user-declared destructor?


The Standard in section 12.8/7 says:

If the class definition does not explicitly declare a copy constructor, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. Thus, for the class definition

struct X {
    X(const X&, int);
};

a copy constructor is implicitly-declared. If the user-declared constructor is later defined as

X::X(const X& x, int i =0) { /∗ ... ∗/ }

I can't get the point of that The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. In the example the Standard neither provides a user-declared copy assignment operator nor a destructor. What will happen if we declare a destructor or a copy assignment operator? I've tried to do that as follows:

struct A
{
    ~A(){ };
};

A::A(const A&){ }; //error

int main(){ }

DEMO

but in the example we still have the implicitly-declared copy constructor. What does that rule actual mean?

I thought that if we write the following:

struct A
{
    A(){ };
    A(const A&&){ };
    ~A(){ };
};

A a;

A t = a; //error: call to implicitly-deleted copy constructor of 'A'

int main()
{ 

}

DEMO

the copy-constructor won't explicitly deleted. But thats's not the case.


Solution

  • This deprecation basically incorporates the Rule of Three (Five). If a user-declared copy assignment operator or destructor is provided, the fact that the copy constructor is defined as defaulted (and not as deleted) is deprecated. That should prevent you from depending upon such an implicitly declared copy constructor in future.

    In the example the Standard provides neither copy assignment nor destructor are user-decalred.

    The example has nothing to do with the deprecation.

    I've tryied to do that as follows: […] but in the example we still have the impliclty-declared copy constructor.

    You cannot define an implicitly declared copy constructor - because it's already defined, by = default (no pun intended). You would have to declare it yourself first.

    I thought that If we wirte the following: […] the copy-constructor won't explicitly deleted. But it's not true.

    You quoted the rule that explicitly specifies that the copy constructor will be implicitly defined as deleted if a move constructor is declared:

    If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted;

    Clearly,

    A(const A&&){ }
    

    Is a move constructor according to [class.copy]/3. If you removed this move constructor then your example compiles, although it uses said deprecated feature.