Die Operatoren new
und delete
C++ unterstützt die dynamische Zuordnung und Zuordnung von Objekten mithilfe der new
Und delete
Operatoren. Diese Operatoren weisen Speicher für Objekte aus einem Pool zu, der als kostenloser Speicher bezeichnet wird (auch als Heap bezeichnet). Der new
Operator ruft die spezielle Funktion operator new
auf, und der delete
Operator ruft die spezielle Funktion operator delete
auf.
Eine Liste der Bibliotheksdateien in der C-Runtime-Bibliothek und der C++-Standardbibliothek finden Sie unter CRT Library Features.
Der new
Operator
Der Compiler übersetzt eine Anweisung wie diese in einen Aufruf der Funktion operator new
:
char *pch = new char[BUFFER_SIZE];
Wenn die Anforderung null Bytes Speicherplatz hat, operator new
wird ein Zeiger auf ein anderes Objekt zurückgegeben. Das heißt, wiederholte Aufrufe, um operator new
unterschiedliche Zeiger zurückzugeben.
Wenn für die Zuordnungsanforderung nicht genügend Arbeitsspeicher vorhanden ist, operator new
wird eine std::bad_alloc
Ausnahme ausgelöst. Oder es wird zurückgegeben nullptr
, wenn Sie das Platzierungsformularnew(std::nothrow)
verwendet haben oder wenn Sie eine Verknüpfung mit nicht ausgelöster operator new
Unterstützung erstellt haben. Weitere Informationen finden Sie unter Zuordnungsfehlerverhalten.
Die beiden Bereiche für operator new
Funktionen werden in der folgenden Tabelle beschrieben.
Bereich für operator new
Funktionen
Operator | `Scope` |
---|---|
::operator new |
Global |
Klassenname::operator new |
Klasse |
Das erste Argument muss operator new
vom Typ size_t
sein, und der Rückgabetyp ist immer void*
.
Die globale operator new
Funktion wird aufgerufen, wenn der new
Operator verwendet wird, um Objekte integrierter Typen, Objekte vom Klassentyp, die keine benutzerdefinierten operator new
Funktionen enthalten, und Arrays eines beliebigen Typs zuzuordnen. Wenn der new
Operator verwendet wird, um Objekte eines Klassentyps zuzuordnen, in dem eine operator new
Klasse definiert ist, wird diese Klasse operator new
aufgerufen.
Eine operator new
für eine Klasse definierte Funktion ist eine statische Memberfunktion (die nicht virtuell sein kann), die die globale operator new
Funktion für Objekte dieses Klassentyps ausblendet. Berücksichtigen Sie den Fall, in dem new
speicherweise einem bestimmten Wert zugewiesen und festgelegt wird:
#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;
}
Das argument, das new
in Klammern angegeben wird, wird als chInit
Argument übergebenBlanks::operator new
. Die globale operator new
Funktion ist jedoch ausgeblendet, was dazu führt, dass Code wie folgt einen Fehler generiert:
Blanks *SomeBlanks = new Blanks;
Der Compiler unterstützt Memberarray new
und delete
Operatoren in einer Klassendeklaration. Beispiel:
class MyClass
{
public:
void * operator new[] (size_t)
{
return 0;
}
void operator delete[] (void*)
{
}
};
int main()
{
MyClass *pMyClass = new MyClass[5];
delete [] pMyClass;
}
Zuordnungsfehlerverhalten
Die new
Funktion in der C++-Standardbibliothek unterstützt das im C++-Standard seit C++98 angegebene Verhalten. Wenn für eine Zuordnungsanforderung nicht genügend Arbeitsspeicher vorhanden ist, operator new
wird eine std::bad_alloc
Ausnahme ausgelöst.
Älterer C++-Code hat einen NULL-Zeiger für eine fehlgeschlagene Zuordnung zurückgegeben. Wenn Sie Code haben, der die nicht ausgelöste Version von new
erwartet, verknüpfen Sie Ihr Programm mit nothrownew.obj
. Die nothrownew.obj
Datei ersetzt global operator new
durch eine Version, die zurückgegeben nullptr
wird, wenn eine Zuordnung fehlschlägt. operator new
wird nicht mehr ausgelöst std::bad_alloc
. Weitere Informationen und nothrownew.obj
andere Linkeroptionsdateien finden Sie unter Linkoptionen.
Sie können keinen Code kombinieren, der auf Ausnahmen von global operator new
mit Code überprüft, der auf Nullzeiger in derselben Anwendung überprüft. Sie können jedoch weiterhin Klassenlokale operator new
erstellen, die sich anders verhalten. Diese Möglichkeit bedeutet, dass der Compiler standardmäßig defensiv agieren muss und Überprüfungen auf NULL-Zeiger-Rückgaben in new
Aufrufen einschließen muss. Weitere Informationen zur Optimierung dieser Compilerprüfungen finden Sie unter /Zc:throwingnew
.
Behandeln von ungenügendem Arbeitsspeicher
Die Art und Weise, wie Sie eine fehlgeschlagene Zuordnung aus einem new
Ausdruck testen, hängt davon ab, ob Sie den Standardausnahmemechanismus verwenden oder eine nullptr
Rückgabe verwenden. Standard C++ erwartet, dass ein Zuweisungsmodul entweder std::bad_alloc
oder eine von der Klasse abgeleitete Klasse ausgelöst wird std::bad_alloc
. Sie können eine solche Ausnahme behandeln, wie in diesem Beispiel gezeigt:
#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;
}
}
Wenn Sie die nothrow
Form verwenden new
, können Sie einen Zuordnungsfehler testen, wie in diesem Beispiel gezeigt:
#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;
}
}
Sie können eine fehlerhafte Speicherzuweisung testen, wenn Sie die Datei verwendet nothrownew.obj
haben, um global operator new
zu ersetzen, wie hier gezeigt:
#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;
}
}
Sie können einen Handler für fehlgeschlagene Speicherzuweisungsanforderungen bereitstellen. Es ist möglich, eine benutzerdefinierte Wiederherstellungsroutine zu schreiben, um einen solchen Fehler zu behandeln. Sie könnte z. B. einen reservierten Speicher freigeben und die Zuweisung dann erneut ausführen lassen. Weitere Informationen finden Sie unter _set_new_handler
.
Der delete
Operator
Speicher, der dynamisch mithilfe des Operators zugewiesen wird, kann über den new
delete
Operator freigegeben werden. Der Löschoperator ruft die operator delete
Funktion auf, die Arbeitsspeicher wieder in den verfügbaren Pool freigibt. Die Verwendung des delete
Operators bewirkt auch, dass der Klassendestruktor (sofern vorhanden) aufgerufen wird.
Es gibt globale und klassenbezogene operator delete
Funktionen. Nur eine operator delete
Funktion kann für eine bestimmte Klasse definiert werden. Wenn definiert, blendet sie die globale operator delete
Funktion aus. Die globale operator delete
Funktion wird immer für Arrays eines beliebigen Typs aufgerufen.
Die globale operator delete
Funktion. Für die globalen operator delete
und Klassenmememmfunktionen operator delete
gibt es zwei Formulare:
void operator delete( void * );
void operator delete( void *, size_t );
Für eine bestimmte Klasse kann nur eine der beiden vorhergehenden Formulare vorhanden sein. Das erste Formular verwendet ein einzelnes Argument vom Typ void *
, das einen Zeiger auf das Objekt zum Deallocate enthält. Das zweite Formular mit der Größe des Deallocation-Vorgangs verwendet zwei Argumente: Der erste ist ein Zeiger auf den Speicherblock, um die Zuordnung zu behandeln, und die zweite ist die Anzahl der Bytes, die zuordnungen. Der Rückgabetyp beider Formulare ist void
(operator delete
kann keinen Wert zurückgeben).
Die Absicht des zweiten Formulars besteht darin, die Suche nach der richtigen Größenkategorie des zu löschenden Objekts zu beschleunigen. Diese Informationen werden häufig nicht in der Nähe der Zuordnung selbst gespeichert und wahrscheinlich nicht zwischengespeichert. Das zweite Formular ist nützlich, wenn eine operator delete
Funktion aus einer Basisklasse verwendet wird, um ein Objekt einer abgeleiteten Klasse zu löschen.
Die operator delete
Funktion ist statisch, sodass sie nicht virtuell sein kann. Die operator delete
Funktion gehorcht der Zugriffssteuerung, wie in der Member-Access-Steuerung beschrieben.
Das folgende Beispiel zeigt benutzerdefinierte operator new
Und operator delete
Funktionen, die zum Protokollieren von Zuordnungen und Deallocations des Arbeitsspeichers entwickelt wurden:
#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;
}
Der vorangehende Code kann verwendet werden, um "Speicherlecks" zu erkennen, d. h. Speicher, der im kostenlosen Speicher zugewiesen ist, aber nie freigegeben wurde. Um Lecks zu erkennen, werden die globalen new
und delete
Operatoren neu definiert, um die Zuordnung und die Zuordnung des Speichers zu zählen.
Der Compiler unterstützt Memberarray new
und delete
Operatoren in einer Klassendeklaration. Beispiel:
// 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;
}
Feedback
https://aka.ms/ContentUserFeedback.
Bald verfügbar: Im Laufe des Jahres 2024 werden wir GitHub-Tickets als Feedbackmechanismus für Inhalte auslaufen lassen und es durch ein neues Feedbacksystem ersetzen. Weitere Informationen finden Sie unter:Feedback senden und anzeigen für