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

noexceptoperator delete()si el constructor se escribe manualmente o se genera implícitamente Lo cual es coherente con mis expectativas: dado que lanewexpresión puede generar una excepción , el compilador debe accederoperator delete().noexcepthará que el código se compile, pero ¿cómo ...?noexceptcomo SebastianRedl mencionó, entoncesoperator deleteno 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:
newLa expresión invoca el correspondienteoperator newy luego llama al constructor. Si el constructor lanza unanewexpresió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, lanewexpresión no puede llamarlo, lo que da como resultado el compiladorerror: use of deleted function 'static void C::operator delete(void*)'.Un
noexceptconstructor no puede lanzar una excepción, por lo tanto, el correspondienteoperator deleteno es necesario ya que no será invocado por unanewexpresión. Undefaultconstructor de una clase trivial también es unnoexceptconstructor. La presencia de un destructor virtual requiereoperator deleteque no se elimine porque se invoca el destructor de eliminación escalar especial (un detalle de implementación para permitir ladeleteexpresió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 deleteque no se elimine, incluso si no es posible llamarlo pornewexpresión.gccSin embargo, no parece ser la invocación de la correspondienteoperator deleteennewla expresión en absoluto si esdeleted (publicado un informe de error ).fuente