Согласно правилам C ++ 11 6 вещей (конструктор по умолчанию, конструктор копирования, конструктор перемещения, назначение копирования, назначение перемещения и деструктор) генерируются по умолчанию. По второму правилу, когда определена любая пользовательская копия, перемещение или деструктор, тогда эти операции по умолчанию не генерируются.
Но в моем коде это не так. Но этот код не компилируется с ошибкой
call to implicitly deleted copy constructor of 'Uni'
Когда я пишу свой собственный конструктор копирования для Uni, все работает нормально. (Это комментируется в коде, приведенном для справки)
Любые мысли высоко ценится.
Наконец, я запускаю это на Mac, XCode с LLVM-компилятором.
большое спасибо…
#include <iostream>
class A
{
public:
A(int i) :num{i}
{
std::clog<< "ctor A() num = " << num << "\n";
}
A( A const &aRef)
:num{aRef.num}
{
std::clog << " copy ctor A( A const &aRef) num = " << num << "\n";
}
int value()
{
return num;
}
private:
int num;
};
class Uni
{
public:
Uni(A* aptr) : up{aptr}
{
std::clog << " ctor Uni value = " << up.get()->value() << "\n";
}
/*Uni(Uni const &uRef)
{
std::clog << " copy ctor Uni copying obj pointed by unique_ptr\n";
up.reset(uRef.up.get() ? new A{*uRef.up.get()} : nullptr);
}*/
private:
std::unique_ptr<A> up;
};
int main(int argc, const char * argv[])
{
Uni one{new A{10}};
Uni two{one}; //default copy ctor is implicitly deleted. why ?
}
Правила автоматического создания специальных членов в C ++ 11 не так просты, как вы их опубликовали. Самое важное различие заключается в том, что в некоторых случаях член неявно объявляется, но определяется как удаленный. Вот что происходит в вашем случае.
C ++ 11, [class.copy] §11:
По умолчанию конструктор копирования / перемещения для класса
X
определяется как удаленный (8.4.3), еслиX
имеет:
- вариант члена с нетривиальным соответствующим конструктором и
X
это союзный класс,- нестатический член данных типа класса
M
(или их массив), которые нельзя скопировать / переместить из-за разрешения перегрузки (13.3) применительно кM
соответствующий конструктор, приводит к неоднозначности или функции, которая удалена или недоступна из конструктора по умолчанию,- прямой или виртуальный базовый класс
B
которые нельзя скопировать / переместить из-за разрешения перегрузки (13.3) применительно кB
соответствующий конструктор, приводит к неоднозначности или функции, которая удалена или недоступна из конструктора по умолчанию,- любой прямой или виртуальный базовый класс или нестатический член данных типа с деструктором, который удален или недоступен из конструктора по умолчанию,
- для конструктора копирования — нестатический член данных ссылочного типа rvalue или
- для конструктора перемещения — нестатический член данных или прямой или виртуальный базовый класс с типом, который не имеет конструктора перемещения и который не может быть легко скопирован.
(Акцент мой)
В более общем плане, правила для автоматически сгенерированных членов класса:
Если в классе нет пользовательских конструкторов, объявляется конструктор по умолчанию.
Если у класса нет предоставленного пользователем конструктора копирования, он объявляется.
Если в классе нет ни одного из {предоставленного пользователем конструктора копирования или перемещения, предоставленного пользователем оператора копирования или перемещения, предоставленного пользователем деструктора}, конструктор перемещения будет объявлен (но см. (*) Ниже).
Если у класса нет предоставленного пользователем оператора копирования, он объявляется.
Если у класса нет ни одного из {предоставленного пользователем конструктора копирования или перемещения, предоставленного пользователем оператора копирования или перемещения, предоставленного пользователем деструктора}, оператор назначения перемещения будет объявлен (но см. (*) Ниже).
Если в классе нет предоставленного пользователем деструктора, он объявляется.
Любой автоматически объявленный элемент может быть определен как дефолтный (выполняется по умолчанию) или определен как удаленный (если вы попытаетесь его использовать, вы получите ошибку). Практическое правило гласит: «Если версия по умолчанию имеет смысл, она будет определена как версия по умолчанию. В противном случае она будет определена как удаленная».
В этом контексте «имеет смысл» означает «не пытается вызывать удаленную, неоднозначную, недоступную или иным образом незаконную функцию». Например, стандартный бит, который я цитировал в первой части этого ответа, перечисляет то, что «не имеет смысла» для конструкторов копирования.
Кроме того, автоматически объявленный конструктор копирования или оператор присваивания копии определяется как удаленный, если в классе имеется предоставленный пользователем конструктор перемещения или оператор присваивания перемещения.
(*) Если автоматически объявленный конструктор перемещения или оператор присваивания перемещения будет определен как удаленный, он вместо этого вообще не объявляется. Это правило существует для того, чтобы попытаться переместить такой класс неявным образом вместо копирования ошибки.
Других решений пока нет …