Funzione operator delete
La memoria allocata in modo dinamico mediante l'operatore new può essere liberata mediante l'operatore delete. L'operatore delete chiama la funzione operator delete , la quale libera la memoria reinserendola nel pool di memoria disponibile. Utilizzando l'operatore delete viene inoltre chiamato il distruttore della classe (se presente).
Sono disponibili funzioni operator delete globali e a livello di ambito della classe. Per una determinata classe è possibile definire una sola funzione operator delete ; qualora definita, questa nasconderà la funzione globale operator delete . La funzione globale operator delete viene sempre chiamata per le matrici di qualsiasi tipo.
La funzione globale operator delete, se dichiarata, accetta un unico argomento di tipo void *, il quale contiene un puntatore all'oggetto da deallocare. Il tipo restituito è void (operator delete non può restituire un valore). Esistono due formati per le funzioni operator delete di membri della classe:
void operator delete( void * );
void operator delete( void *, size_t );
Per una determinata classe può essere presente solo una delle due varianti precedenti. Il primo formato funziona come descritto per la funzione operator deleteglobale. Il secondo formato accetta due argomenti, il primo dei quali è un puntatore al blocco di memoria da deallocare e il secondo è il numero di byte da deallocare. Il secondo formato è particolarmente utile quando una funzione operator delete di una classe base viene utilizzata per eliminare un oggetto di una classe derivata.
La funzione operator delete è statica; pertanto, non può essere virtuale. La funzione operator delete obbedisce al controllo di accesso, come descritto in Controllo dell'accesso ai membri.
Il seguente esempio mostra le funzioni definite dall'utente operator new e operator delete , progettate per registrare le allocazioni e le deallocazioni della memoria:
Esempio
// spec1_the_operator_delete_function1.cpp
// compile with: /EHsc
// arguments: 3
#include <iostream>
using namespace std;
int fLogMemory = 0; // Perform logging (0=no; nonzero=yes)?
int cBlocksAllocated = 0; // Count of blocks allocated.
// User-defined operator new.
void *operator new( size_t stAllocateBlock ) {
static int fInOpNew = 0; // Guard flag.
if ( fLogMemory && !fInOpNew ) {
fInOpNew = 1;
clog << "Memory block " << ++cBlocksAllocated
<< " allocated for " << stAllocateBlock
<< " bytes\n";
fInOpNew = 0;
}
return malloc( stAllocateBlock );
}
// User-defined operator delete.
void operator delete( void *pvMem ) {
static int fInOpDelete = 0; // Guard flag.
if ( fLogMemory && !fInOpDelete ) {
fInOpDelete = 1;
clog << "Memory block " << cBlocksAllocated--
<< " deallocated\n";
fInOpDelete = 0;
}
free( pvMem );
}
int main( int argc, char *argv[] ) {
fLogMemory = 1; // Turn logging on
if( argc > 1 )
for( int i = 0; i < atoi( argv[1] ); ++i ) {
char *pMem = new char[10];
delete[] pMem;
}
fLogMemory = 0; // Turn logging off.
return cBlocksAllocated;
}
A partire da Visual C++ 5.0, il compilatore supporta gli operatori new e delete della matrice di membro in una dichiarazione di classe. Ad esempio:
// spec1_the_operator_delete_function2.cpp
// compile with: /c
class X {
public:
void * operator new[] (size_t) {
return 0;
}
void operator delete[] (void*) {}
};
void f() {
X *pX = new X[5];
delete [] pX;
}
Commento
Il codice precedente può essere utilizzato per rilevare le "perdite di memoria", ovvero della memoria allocata nell'archiviazione disponibile ma che non viene mai liberata. Per eseguire questo rilevamento, gli operatori new e delete vengono ridefiniti per contare l'allocazione e la deallocazione di memoria.