Стандарт в разделе 12.8 / 7 гласит:
Если определение класса явно не объявляет копию
конструктор, один объявлен неявно. Если определение класса
объявляет конструктор перемещения или оператор присваивания перемещения,
неявно объявленный конструктор копирования определяется как удаленный; иначе,
это определяется как дефолт (8.4). Последний случай считается устаревшим, если
класс имеет объявленный пользователем оператор копирования или пользовательский
деструктор. Таким образом, для определения классаstruct X { X(const X&, int); };
конструктор копирования неявно объявлен. Если пользователь объявил
Конструктор позже определяется какX::X(const X& x, int i =0) { /∗ ... ∗/ }
Я не могу понять суть этого Последний случай считается устаревшим, если в классе есть объявленный пользователем оператор копирования или объявленный пользователем деструктор. В этом примере Стандарт не предоставляет ни оператора, назначенного пользователем для копирования, ни деструктора. Что произойдет, если мы объявим деструктор или оператор присваивания копии? Я попытался сделать это следующим образом:
struct A
{
~A(){ };
};
A::A(const A&){ }; //error
int main(){ }
но в примере у нас все еще есть неявно объявленный конструктор копирования. Что означает это правило на самом деле?
Я думал, что если мы напишем следующее:
struct A
{
A(){ };
A(const A&&){ };
~A(){ };
};
A a;
A t = a; //error: call to implicitly-deleted copy constructor of 'A'
int main()
{
}
конструктор копирования не будет явно удален. Но это не тот случай.
Этот износ в основном включает в себя правило трех (пять). Если предоставлен пользовательский оператор или деструктор назначения копирования, тот факт, что конструктор копирования определен как дефолтный (а не как удаленный), считается устаревшим. Это должно помешать вам в будущем зависеть от такого неявно объявленного конструктора копирования.
В примере стандарт не предусматривает ни копирования, ни
деструктор деколируется пользователем.
Пример не имеет ничего общего с устареванием.
Я попытался сделать это следующим образом: […] но в примере у нас все еще есть объявленная имплицитом копия
конструктор.
Вы не можете определить неявно объявленный конструктор копирования — потому что он уже определен = default
(каламбур не предназначен). Вы должны были бы сначала заявить об этом сами.
Я думал, что если мы напишем следующее: […] конструктор копирования не будет удален явно. Но это не правда.
Вы процитировал правило, которое явно указывает, что конструктор копирования будет неявно определен как удаленный, если объявлен конструктор перемещения:
Если определение класса объявляет конструктор перемещения или перемещение
оператор присваивания, неявно объявленный конструктор копирования
определяется как удаленный;
Очевидно, что
A(const A&&){ }
Является конструктором перемещения в соответствии с [class.copy] / 3. Если вы удалили этот конструктор перемещения, то ваш пример компилируется, хотя он использует устаревшую функцию.
«Устаревшее» обычно означает, что что-то будет работать, но что оно будет осуждено и может не сработать в будущем. Я думаю, что стандарт гласит, что если вы создадите объявленный пользователем оператор копирования или деструктор, объявленный пользователем, он все равно создаст конструктор копирования по умолчанию (если вы этого не сделали), но это может произойти не в будущем. Поэтому они хотят, чтобы вы создали свой собственный конструктор копирования сейчас, если у вас есть один из двух других, и в будущем они могут вас заставить.