Operatori new
e delete
C++ supporta l'allocazione dinamica e la deallocazione degli oggetti usando gli new
operatori e delete
. Questi operatori allocano memoria per gli oggetti da un pool denominato archivio gratuito (noto anche come heap). L'operatore new
chiama la funzione operator new
speciale e l'operatore delete
chiama la funzione operator delete
speciale .
Per un elenco dei file di libreria nella libreria di runtime C e nella libreria standard C++, vedere Funzionalità della libreria CRT.
new
Operatore
Il compilatore converte un'istruzione come questa in una chiamata alla funzione operator new
:
char *pch = new char[BUFFER_SIZE];
Se la richiesta è per zero byte di spazio di archiviazione, operator new
restituisce un puntatore a un oggetto distinto. Vale a dire, chiamate ripetute per operator new
restituire puntatori diversi.
Se la memoria per la richiesta di allocazione non è sufficiente, operator new
genera un'eccezione std::bad_alloc
. In alternativa, restituisce nullptr
se è stato usato il modulo new(std::nothrow)
di posizionamento o se è stato collegato il supporto non generanteoperator new
. Per altre informazioni, vedere Comportamento degli errori di allocazione.
I due ambiti per operator new
le funzioni sono descritti nella tabella seguente.
Ambito delle operator new
funzioni
Operatore | Ambito |
---|---|
::operator new |
Generale |
class-name::operator new |
Classe |
Il primo argomento di operator new
deve essere di tipo size_t
e il tipo restituito è sempre void*
.
La funzione globale operator new
viene chiamata quando l'operatore new
viene usato per allocare oggetti di tipi predefiniti, oggetti di tipo classe che non contengono funzioni definite dall'utente operator new
e matrici di qualsiasi tipo. Quando l'operatore new
viene usato per allocare oggetti di un tipo di classe in cui è definito un operator new
oggetto , viene chiamato tale operator new
classe.
Una operator new
funzione definita per una classe è una funzione membro statica (che non può essere virtuale) che nasconde la funzione globale operator new
per gli oggetti di tale tipo di classe. Si consideri il caso in cui new
viene usato per allocare e impostare la memoria su un valore specificato:
#include <malloc.h>
#include <memory.h>
class Blanks
{
public:
Blanks(){}
void *operator new( size_t stAllocateBlock, char chInit );
};
void *Blanks::operator new( size_t stAllocateBlock, char chInit )
{
void *pvTemp = malloc( stAllocateBlock );
if( pvTemp != 0 )
memset( pvTemp, chInit, stAllocateBlock );
return pvTemp;
}
// For discrete objects of type Blanks, the global operator new function
// is hidden. Therefore, the following code allocates an object of type
// Blanks and initializes it to 0xa5
int main()
{
Blanks *a5 = new(0xa5) Blanks;
return a5 != 0;
}
L'argomento fornito tra parentesi a new
viene passato come Blanks::operator new
chInit
argomento. Tuttavia, la funzione globale operator new
è nascosta, causando il codice come il seguente per generare un errore:
Blanks *SomeBlanks = new Blanks;
Il compilatore supporta operatori e delete
matrici new
membro in una dichiarazione di classe. Ad esempio:
class MyClass
{
public:
void * operator new[] (size_t)
{
return 0;
}
void operator delete[] (void*)
{
}
};
int main()
{
MyClass *pMyClass = new MyClass[5];
delete [] pMyClass;
}
Comportamento degli errori di allocazione
La new
funzione nella libreria standard C++ supporta il comportamento specificato nello standard C++ a partire da C++98. Quando la memoria per una richiesta di allocazione non è sufficiente, operator new
genera un'eccezione std::bad_alloc
.
Il codice C++ precedente ha restituito un puntatore Null per un'allocazione non riuscita. Se si dispone di codice che prevede la versione non generata di new
, collegare il programma a nothrownew.obj
. Il nothrownew.obj
file sostituisce global operator new
con una versione che restituisce nullptr
se un'allocazione non riesce. operator new
non genera std::bad_alloc
più . Per altre informazioni su nothrownew.obj
e altri file di opzioni del linker, vedere Opzioni di collegamento.
Non è possibile combinare codice che verifica la presenza di eccezioni da globale operator new
con codice che verifica la presenza di puntatori Null nella stessa applicazione. Tuttavia, è comunque possibile creare classi locali operator new
che si comportano in modo diverso. Questa possibilità significa che il compilatore deve agire difensivamente per impostazione predefinita e includere controlli per i ritorni del puntatore Null nelle new
chiamate. Per altre informazioni su un modo per ottimizzare questi controlli del compilatore, vedere /Zc:throwingnew
.
Gestione della memoria insufficiente
Il modo in cui si esegue il test per un'allocazione non riuscita da un'espressione new
dipende dal fatto che si usi il meccanismo di eccezione standard o si usa un nullptr
valore restituito. Standard C++ prevede che un allocatore generi std::bad_alloc
un'eccezione o una classe derivata da std::bad_alloc
. È possibile gestire un'eccezione di questo tipo, come illustrato in questo esempio:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
try {
int *pI = new int[BIG_NUMBER];
}
catch (bad_alloc& ex) {
cout << "Caught bad_alloc: " << ex.what() << endl;
return -1;
}
}
Quando si usa il nothrow
formato di , è possibile verificare se si verifica un errore di new
allocazione, come illustrato in questo esempio:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new(nothrow) int[BIG_NUMBER];
if ( pI == nullptr ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
È possibile testare l'allocazione di memoria non riuscita quando è stato usato nothrownew.obj
il file per sostituire globale operator new
, come illustrato di seguito:
#include <iostream>
#include <new>
using namespace std;
#define BIG_NUMBER 10000000000LL
int main() {
int *pI = new int[BIG_NUMBER];
if ( !pI ) {
cout << "Insufficient memory" << endl;
return -1;
}
}
È possibile fornire un gestore per le richieste di allocazione di memoria non riuscite. È possibile scrivere una routine di ripristino personalizzata per gestire un errore di questo tipo. Potrebbe, ad esempio, rilasciare una memoria riservata, quindi consentire l'esecuzione dell'allocazione di nuovo. Per ulteriori informazioni, vedere _set_new_handler
.
delete
Operatore
La memoria allocata dinamicamente tramite l'operatore new
può essere liberata usando l'operatore delete
. L'operatore delete chiama la operator delete
funzione , che libera memoria al pool disponibile. L'uso dell'operatore delete
fa anche in modo che venga chiamato il distruttore di classe (se esistente).
Sono disponibili funzioni globali e con ambito operator delete
di classe. È possibile definire una operator delete
sola funzione per una determinata classe; se definita, nasconde la funzione globale operator delete
. La funzione globale operator delete
viene sempre chiamata per matrici di qualsiasi tipo.
Funzione globale operator delete
. Esistono due forme per le funzioni membro globali operator delete
e di operator delete
classe:
void operator delete( void * );
void operator delete( void *, size_t );
Solo una delle due forme precedenti può essere presente per una determinata classe. La prima maschera accetta un singolo argomento di tipo void *
, che contiene un puntatore all'oggetto da deallocare. Il secondo formato, la deallocazione delle dimensioni, accetta due argomenti: il primo è un puntatore al blocco di memoria da deallocare e il secondo è il numero di byte da deallocare. Il tipo restituito di entrambi i moduli è void
(operator delete
non può restituire un valore).
La finalità del secondo modulo consiste nel velocizzare la ricerca della categoria di dimensioni corretta dell'oggetto da eliminare. Queste informazioni spesso non vengono archiviate vicino all'allocazione stessa e probabilmente non sono memorizzate nella cache. Il secondo modulo è utile quando viene usata una operator delete
funzione di una classe base per eliminare un oggetto di una classe derivata.
La operator delete
funzione è statica, quindi non può essere virtuale. La operator delete
funzione rispetta il controllo di accesso, come descritto in Member-Controllo di accesso.
L'esempio seguente illustra le funzioni definite operator delete
dall'utente operator new
progettate per registrare allocazioni e deallocazione della memoria:
#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;
}
Il codice precedente può essere usato per rilevare la "perdita di memoria", ovvero la memoria allocata nell'archivio gratuito, ma mai liberata. Per rilevare le perdite, gli operatori globali new
e delete
vengono ridefinti in modo da contare l'allocazione e la deallocazione della memoria.
Il compilatore supporta operatori e delete
matrici new
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;
}
Commenti e suggerimenti
https://aka.ms/ContentUserFeedback.
Presto disponibile: Nel corso del 2024 verranno gradualmente disattivati i problemi di GitHub come meccanismo di feedback per il contenuto e ciò verrà sostituito con un nuovo sistema di feedback. Per altre informazioni, vedereInvia e visualizza il feedback per