Crear un nuevo objeto de clase C con el operador new () da un error aquí:
class C
{
public:
C() {}
virtual ~C() {}
void operator delete(void*) = delete;
};
int main()
{
C* c = new C;
}
con C2280: 'void C::operator delete(void *)': function was explicitly deleted
Pero cuando sustituyo C() {}
con C() = default;
o elimino la línea para que el compilador inserta un constructor por defecto (que creo que tiene el mismo efecto con = default
), el código se compila y corre.
¿Cuáles son las diferencias entre el constructor predeterminado generado por el compilador y el constructor predeterminado definido por el usuario que hacen que esto suceda?
Tengo alguna pista en esta publicación , pero la clase C aquí (sin el constructor proporcionado por el usuario) no es trivial ya que el destructor es virtual, ¿verdad?
Compilado con la última versión de Visual Studio, c ++ 17.
fuente
noexcept
operator delete()
si el constructor se escribe manualmente o se genera implícitamente Lo cual es coherente con mis expectativas: dado que lanew
expresión puede generar una excepción , el compilador debe accederoperator delete()
.noexcept
hará que el código se compile, pero ¿cómo ...?noexcept
como SebastianRedl mencionó, entoncesoperator delete
no es necesario incluir una llamada . Además, g ++ solo se queja si el destructor es virtual. De lo contrario, siempre se compila, incluso si el constructor está lanzando.Respuestas:
new
La expresión invoca el correspondienteoperator new
y luego llama al constructor. Si el constructor lanza unanew
expresión de excepción , debe deshacer el efecto deoperator new
(para evitar pérdidas de memoria) llamando al correspondienteoperator delete
. Si se elimina esta última, lanew
expresión no puede llamarlo, lo que da como resultado el compiladorerror: use of deleted function 'static void C::operator delete(void*)'
.Un
noexcept
constructor no puede lanzar una excepción, por lo tanto, el correspondienteoperator delete
no es necesario ya que no será invocado por unanew
expresión. Undefault
constructor de una clase trivial también es unnoexcept
constructor. La presencia de un destructor virtual requiereoperator delete
que no se elimine porque se invoca el destructor de eliminación escalar especial (un detalle de implementación para permitir ladelete
expresión a través del puntero de la clase base)operator delete
.Parece que el estándar C ++ no especifica si el compilador debe requerir
operator delete
que no se elimine, incluso si no es posible llamarlo pornew
expresión.gcc
Sin embargo, no parece ser la invocación de la correspondienteoperator delete
ennew
la expresión en absoluto si esdelete
d (publicado un informe de error ).fuente