C++ Error del compilador C2280 "al intentar hacer referencia a una función eliminada" en Visual Studio 2013 y 2015
visual-c++ copy-constructor (3)
Este fragmento de código se compila sin errores en Visual Studio 2013 (Versión 12.0.31101.00 Actualización 4)
class A
{
public:
A(){}
A(A &&){}
};
int main(int, char*)
{
A a;
new A(a);
return 0;
}
mientras se compila con este error en Visual Studio 2015 RC (versión 14.0.22823.1 D14REL):
1>------ Build started: Project: foo, Configuration: Debug Win32 ------
1> foo.cpp
1>c:/dev/foo/foo.cpp(11): error C2280: ''A::A(const A &)'': attempting to reference a deleted function
1> c:/dev/foo/foo.cpp(6): note: compiler has generated ''A::A'' here
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Creo que el compilador que se incluye con Visual Studio 2015 genera el Constructor de Copias y lo marca como =delete
y así obtengo el error C2280 (que, por cierto, no puedo encontrar documentado en msdn.microsoft.com).
Ahora, digamos que tengo un código base compilable con Visual Studio 2013 (y funciona porque se basa en el código generado automáticamente por el compilador) pero no compilable con Visual Studio 2015 debido a C2280, ¿cómo puedo solucionar el problema?
Estaba pensando declarar la clase A
de esta manera:
class A
{
public:
A(){}
A(A &&){}
A(const A&)=default;
};
¿Me estoy perdiendo de algo?
De [class.copy] / 7, énfasis mío:
Si la definición de la clase no declara explícitamente un constructor de copia, se declara implícitamente uno no explícito. Si la definición de clase declara un constructor de movimiento o un operador de asignación de movimiento, el constructor de copia declarado implícitamente se define como eliminado ; de lo contrario, se define como predeterminado (8.4). El último caso queda en desuso si la clase tiene un operador de asignación de copia declarado por el usuario o un destructor declarado por el usuario.
Hay una sección equivalente con una redacción similar para la asignación de copias en el párrafo 18. Así que su clase es realmente:
class A
{
public:
// explicit
A(){}
A(A &&){}
// implicit
A(const A&) = delete;
A& operator=(const A&) = delete;
};
Es por eso que no puedes copiarlo-construirlo. Si proporciona un constructor / asignación de movimiento y aún desea que la clase se pueda copiar, tendrá que proporcionar explícitamente esas funciones miembro especiales:
A(const A&) = default;
A& operator=(const A&) = default;
También deberá declarar un operador de asignación de movimiento. Si realmente necesita estas funciones especiales, probablemente también necesitará el destructor. Ver Regla de los Cinco .
Si escribe un constructor de movimiento definido por el usuario para su clase, se eliminará el constructor de copia. Esto se debe a que si una clase necesita un comportamiento especial para su constructor de movimiento, es probable que necesite un comportamiento similar en su constructor de copia, por lo que el constructor de copia se eliminará para evitar que use inadvertidamente el comportamiento predeterminado.
Si desea definir su propio constructor de movimiento y usar el constructor de copia predeterminado, debe declararlo como default
, como sugirió en su pregunta:
class A
{
public:
A(){}
A(A &&){}
//I know what I''m doing, compiler, use the default version.
A(const A&)=default;
};
Tenga en cuenta que si define un constructor de movimiento personalizado, también debería pensar en los operadores de asignación y el destructor.
Tuve el mismo problema y se debió a una variable miembro mal definida:
double const deltaBase = .001;
Poner esto hará que se elimine el constructor de copia. Deshazte de la "const" y asigna en el constructor.