operator assignment c++ c++11 default-copy-constructor

c++ - assignment - Llamada al constructor de copia suprimido implícitamente en LLVM



copy constructor struct c++ (1)

De acuerdo con las reglas de C ++ 11, 6 cosas (constructor predeterminado, constructor de copia, constructor de movimiento, asignación de copia, asignación de movimiento y destructor) se generan de forma predeterminada. Por la segunda regla, cuando se define cualquier copia, movimiento o destructor personalizados, no se generan esas operaciones predeterminadas. Pero en mi código que sigue ese no es el caso. Pero este código no se compila con un error

call to implicitly deleted copy constructor of ''Uni''

Cuando escribo mi propio constructor de copia para Uni, todo funciona bien. (Se comenta en el código, dado como referencia).

Cualquier pensamiento muy apreciado.

Finalmente, estoy ejecutando esto en Mac, Xcode con el compilador LLVM.

muchas gracias...

#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 ? }


Las reglas de C ++ 11 para la generación automática de miembros especiales no son tan simples como las publicaste. La distinción más importante es que en algunos casos, el miembro se declara implícitamente, pero se define como eliminado. Eso es lo que pasa en tu caso.

C ++ 11, [class.copy] §11:

Un constructor predeterminado de copiar / mover para una clase X se define como eliminado (8.4.3) si X tiene:

  • un miembro variante con un constructor correspondiente no trivial y X es una clase similar a una unión,
  • un miembro de datos no estáticos de clase de clase M (o matriz de los mismos) que no se puede copiar / mover debido a que la resolución de sobrecarga (13.3), aplicada al constructor correspondiente de M , resulta en una ambigüedad o una función que se elimina o es inaccesible desde el constructor por defecto,
  • una clase base directa o virtual B que no se puede copiar / mover debido a que la resolución de sobrecarga (13.3), aplicada al constructor correspondiente de B , resulta en una ambigüedad o una función que se elimina o es inaccesible desde el constructor predeterminado,
  • cualquier clase de base directa o virtual o miembro de datos no estáticos de un tipo con un destructor que se elimine o sea inaccesible desde el constructor predeterminado,
  • para el constructor de copia, un miembro de datos no estáticos de tipo de referencia rvalue, o
  • para el constructor de movimientos, un miembro de datos no estáticos o una clase base directa o virtual con un tipo que no tiene un constructor de movimientos y no se puede copiar de forma trivial.

(Énfasis mío)

Más generalmente, las reglas para los miembros de la clase generados automáticamente son:

  • Si la clase no tiene constructores proporcionados por el usuario, se declara un constructor predeterminado.

  • Si la clase no tiene un constructor de copia proporcionado por el usuario, se declara uno.

  • Si la clase no tiene {constructor de movimiento o copia proporcionado por el usuario, operador de asignación de movimiento o copia provisto por el usuario, destructor provisto por el usuario}, se declarará un constructor de movimiento (pero vea (*) a continuación).

  • Si la clase no tiene un operador de asignación de copia provisto por el usuario, se declara uno.

  • Si la clase no tiene {constructor de movimiento o copia provisto por el usuario, operador de asignación de movimiento o copia provisto por el usuario, destructor provisto por el usuario}, se declarará un operador de asignación de movimiento (pero vea (*) a continuación).

  • Si la clase no tiene un destructor proporcionado por el usuario, se declara uno.

Cualquier miembro declarado automáticamente puede definirse como predeterminado (hacer las cosas predeterminadas) o definido como eliminado (si intenta usarlo, obtiene un error). La regla de oro es "Si la versión predeterminada tiene sentido, se definirá como predeterminada. De lo contrario, se definirá como eliminada".

En este contexto, "tiene sentido" significa "no intenta llamar a una función eliminada, ambigua, inaccesible o ilegal". Por ejemplo, el bit estándar que cité en la primera parte de esta respuesta enumera lo que no tiene "sentido" para los constructores de copias.

Además, un constructor de copia o operador de asignación de copia declarado automáticamente se define como eliminado si la clase tiene un constructor de movimiento proporcionado por el usuario o un operador de asignación de movimiento.

(*) Si un constructor de movimiento o un operador de asignación de movimiento declarado automáticamente se definiría como eliminado, en su lugar no se declarará en absoluto. Esta regla existe, de modo que al intentar mover una clase de este tipo, implícitamente se vuelve a copiar en lugar de generar un error.