ProgrammazioneSviluppatore C++, Programmatore di sistema

Racconta del meccanismo operator new/operator delete in C++. Come si differenziano da new/delete, quando e perché le funzioni operatore vengono sovrascritte nelle classi utente?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

In C++ operator new e operator delete sono funzioni di allocazione e liberazione della memoria che vengono chiamate durante la creazione e la rimozione di oggetti tramite gli operatori new e delete. Per impostazione predefinita, utilizzano l'allocatore standard, ma nella classe possono essere sovrascritte per un controllo più fine sull'allocazione di memoria.

  • operator new alloca un'area di memoria "grezza", senza chiamare il costruttore.
  • Dopo l'allocazione della memoria, viene automaticamente chiamato il costruttore dell'oggetto.
  • operator delete libera la memoria dopo la conclusione del distruttore dell'oggetto.

Utilizzo (versioni globali e locali):

  • La versione globale viene applicata per impostazione predefinita (ad esempio, in new int).
  • Sovrascrivendo in una classe un operator new specifico, è possibile ottimizzare l'uso della memoria per gli oggetti di quella classe (ad esempio, pool di oggetti, tracciamento, riutilizzo dei blocchi).

Esempio di sovraccarico di operator new/operator delete:

#include <iostream> class TrackAlloc { public: void* operator new(size_t size) { std::cout << "TrackAlloc::new per " << size << " bytes "; return ::operator new(size); } void operator delete(void* ptr) { std::cout << "TrackAlloc::delete "; ::operator delete(ptr); } };

Dettagli:

  • La chiamata a nuovi/rimozione di oggetti con argomenti (placement new) richiede una sovrascrittura separata.
  • Gli operatori sovrascritti vengono chiamati solo durante la creazione/rimozione di oggetti di classe, non per new[]/delete[]. Per loro è possibile sovrascrivere operator new[]/delete[] separati.
  • Le manipolazioni della memoria sono pericolose: è necessaria una corretta gestione delle eccezioni.

Domanda trabocchetto.

"Cosa succede se si sovrascrive l'operatore new in una classe e poi si crea un oggetto tramite una variabile di una classe derivata? Quale versione di operator new verrà chiamata?"

Risposta: Verrà chiamato l'operator new della classe dalla quale viene creato l'oggetto. Se nella classe derivata non è implementato l'operator new, si tenterà di trovare una versione appropriata nella classe base o la versione globale.

Esempio:

struct Base { void* operator new(size_t s) { std::cout << "Base new "; return ::operator new(s); } }; struct Derived : Base {}; Derived* p = new Derived; // Chiamerà Base::operator new!

Esempi di errori reali dovuti alla mancanza di conoscenza delle sottigliezze dell'argomento.


Storia

Gli sviluppatori hanno sovrascritto operator new/ delete senza supporto per una corretta gestione delle eccezioni. Quando si lanciava un'eccezione all'interno del costruttore, la memoria non veniva liberata, portando a perdite di memoria.


Storia

Implementato in modo errato operator new[] e operator delete[]: per la classe, all'interno della quale erano contenuti array, la nuova implementazione non veniva chiamata — venivano utilizzate le versioni di default, portando a una dissincronizzazione della logica di allocazione e liberazione della memoria.


Storia

La sovrascrittura dell'operatore new globale ha influenzato il funzionamento delle librerie di terze parti: tutti gli oggetti (compresi temporanei e da STL) hanno iniziato ad essere allocati tramite l'allocatore registrato, il che ha rallentato critticamente il funzionamento del nucleo dell'applicazione.