virtuales puro polimorfismo metodo herencia funciones clase abstracta c++ c++11 destructor virtual-functions

metodo - polimorfismo puro c++



¿Por qué necesitamos usar virtual ~ A()=predeterminado? en lugar de virtual ~ A(){} en C++ 11? (3)

En este post https://stackoverflow.com/a/17204598/260127 , tengo el comentario:

En C ++ 11, en realidad querrás hacer virtual ~A() = default; De lo contrario, perderás los constructores de movimiento implícito.

El comentario es incorrecto

Incluso ed por default , ese destructor es " declarado por el usuario " (aunque tenga en cuenta que no es también " proporcionado por el usuario ").

#include <iostream> struct Helper { Helper() {} Helper(const Helper& src) { std::cout << "copy/n"; } Helper(Helper&& src) { std::cout << "move/n"; } }; struct A { virtual ~A() {} Helper h; }; struct B { virtual ~B() = default; Helper h; }; struct C { Helper h; }; int main() { { A x; A y(std::move(x)); // outputs "copy", because no move possible } { B x; B y(std::move(x)); // outputs "copy", because still no move possible } { C x; C y(std::move(x)); // outputs "move", because no user-declared dtor } }

Demostración en vivo :

+ g ++ - 4.8 -std = c ++ 11 -O2 -Wall -pthread main.cpp
+ ./a.out
dupdo
dupdo
movimiento

Entonces no has "perdido" nada, ¡no había ninguna funcionalidad de movimiento allí para empezar!

Aquí está el pasaje estándar que prohíbe un constructor de movimiento implícito en ambos casos:

[C++11: 12.8/9]: si la definición de una clase X no declara explícitamente un constructor de movimiento, se declarará implícitamente como predeterminada si y solo si

  • X no tiene un constructor de copia declarado por el usuario,
  • X no tiene un operador de asignación de copia declarado por el usuario,
  • X no tiene un operador de asignación de movimiento declarado por el usuario,
  • X no tiene un destructor declarado por el usuario , y
  • el constructor de movimiento no se definiría implícitamente como eliminado.

Bootnote

No estaría de más que una versión futura de la norma enlistara los significados exactos de los términos como "declarado por el usuario". Hay, al menos, esto:

[C++11: 8.4.2/4]: [..] Una función de miembro especial es proporcionada por el usuario si es declarada por el usuario y no está explícitamente predeterminada o eliminada en su primera declaración. [..]

Uno puede asumir la distinción aquí por implicación.

En la publicación Stack Overflow Comprobando el tipo de objeto en C ++ 11 , tengo el siguiente comentario:

En C ++ 11, en realidad querrás hacer virtual ~A() = default; De lo contrario, perderás los constructores de movimiento implícito.

¿Qué es virtual ~A() = default; ¿para? ¿Cómo es que los constructores de movimiento implícitos se pierden con virtual ~A() {} ?


El comentario no es correcto

Ambos:

virtual ~A() = default;

y

virtual ~A() {}

son declarados por el usuario Y los miembros de movimiento implícitos están inhibidos si el destructor es declarado por el usuario.

[dcl.fct.def.default] / p4 analiza los miembros especiales declarados por el usuario y proporcionados por el usuario :

Una función de miembro especial es proporcionada por el usuario si es declarada por el usuario y no está explícitamente predeterminada o eliminada en su primera declaración.


Ese comentario es incorrecto

En lugar de proporcionar su propio constructor de movimientos, si desea que el compilador proporcione uno, uno de los requisitos es que espera que el destructor también lo proporcione, es decir, un destructor trivial. Sin embargo, el estándar actual es bastante estricto sobre cuándo se puede proporcionar una implementación implícita, al aceptar cómo un destructor es dado por el usuario. Cualquier cosa declarada por el usuario se considera que el usuario está tomando el asunto en sus propias manos y por lo tanto no solo esto

~A() { … }

pero también esto

~A() = default;

hace que el compilador no proporcione un destructor implícito. Primero es una definición y, por lo tanto, también una declaración; el segundo es solo una declaración. En ambos casos, el usuario declara el destructor y, por lo tanto, prohíbe al compilador proporcionar un constructor de movimiento implícito.

Supongo que la razón detrás del requisito es que durante el movimiento los recursos de un objeto se muevan a otro objeto dejando el objeto original en un estado donde no tiene recursos en el almacenamiento dinámico; pero si su clase no tiene tales recursos, puede ser trivial movida, destruida, etc. Cuando declara un destructor no trivial, es una señal para el compilador de que los recursos que maneja en la clase no son algo trivial y que en su mayoría, también debe proporcionar movimientos no triviales, por lo que el compilador no proporciona ninguno.