L'operatore new () si comporta diversamente quando l'operatore delete () viene eliminato in base all'esistenza del costruttore predefinito


17

La creazione di un nuovo oggetto di classe C con l'operatore new () genera un errore qui:

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

Ma quando sostituisce C() {} con C() = default; o rimuovere la riga in modo che compilatore inserisce un costruttore di default (che ritengo ha lo stesso effetto con = default), il codice verrà compilare ed eseguire.

Quali sono le differenze tra il costruttore predefinito generato dal compilatore e il costruttore predefinito definito dall'utente che lo rendono possibile?

Ho avuto qualche suggerimento in questo post , ma la classe C qui (senza costruttore fornito dall'utente) non è banale poiché il distruttore è virtuale, giusto?

Compilato con l'ultimo Visual Studio, c ++ 17.


3
Non sono sicuro, ma penso che la differenza è che il costruttore in default ènoexcept
Sebastian Redl

1
Impossibile riprodurre con g ++. Diagnostica simile per operator delete()stabilire se il costruttore è scritto manualmente o generato implicitamente. Il che è coerente con le mie aspettative - poiché l' newespressione può generare un'eccezione , il compilatore deve accedere operator delete().
Peter,

@SebastianRedl hai ragione, l'aggiunta noexceptfarà compilare il codice, ma come ...?
yeshjho,

1
@Peter L'eccezione può essere generata solo dal costruttore, quindi se è noexceptcome menzionato SebastianRedl, operator deletenon è necessario includere una chiamata . Inoltre g ++ si lamenta solo se il distruttore è virtuale. Altrimenti si compila sempre, anche se il costruttore sta lanciando.
noce,

@LeDYoM Il tuo link riguarda l'analisi degli indirizzi IP, che sembra essere irrilevante per la domanda. Hai pubblicato un link sbagliato?
LF

Risposte:


17

Quali sono le differenze tra il costruttore predefinito generato dal compilatore e il costruttore predefinito definito dall'utente che lo rendono possibile?

newL'espressione invoca il corrispondente operator newe quindi chiama il costruttore. Se il costruttore genera newun'espressione di eccezione , è necessario annullare l'effetto di operator new(per evitare perdite di memoria) chiamando il corrispondente operator delete. Se quest'ultima viene eliminata, l' newespressione non può chiamarla, il che provoca il compilatore error: use of deleted function 'static void C::operator delete(void*)'.

Un noexceptcostruttore non può lanciare un'eccezione, quindi il corrispondente operator deletenon è necessario in quanto non verrà chiamato da newun'espressione. Un defaultcostruttore di una classe banale è anche un noexceptcostruttore. La presenza di un distruttore virtuale richiede operator deletedi non essere eliminata perché viene invocato lo speciale distruttore che elimina il distruttore (un dettaglio dell'implementazione per abilitare l' deleteespressione tramite il puntatore della classe base) operator delete.

Sembra non essere specificato dallo standard C ++ se il compilatore debba richiedere operator deletedi non essere cancellato anche se non può essere chiamato newdall'espressione. gcc, Tuttavia, non sembra essere invocando il corrispondente operator deletein newespressione a tutti se si tratta deleted (inviato un bug report ).

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.