C/C++-Speicherverwaltung (ausführliche Erklärung zum Neuen und Löschen)

Einführung

Im vorherigen Teil der C-Sprache haben wir die Aufteilung der Speicherbereiche im Speicher eingeführt: einschließlich Kernel-Speicherplatz (Benutzercode kann nicht darauf zugreifen), Stapel, Speicherzuordnungssegment (Dateizuordnung, dynamische Bibliothek, anonyme Zuordnung), Heap, Datensegment ( statischer Bereich), Codesegment (konstanter Bereich) .
Und Sie können malloc, calloc, realloc und free geschickt für die dynamische Speicherverwaltung verwenden:
Details zur dynamischen Speicherverwaltung in C-Sprache

Wenn diese Funktionen in C++ jedoch für die dynamische Speicherverwaltung verwendet werden, können einige Anforderungen nicht erfüllt werden (z. B. das Initialisieren von Objekten bei der Beantragung von Speicherplatz) und die Verwendung ist problematischer. newDaher schlägt C++ eine Möglichkeit vor, dynamisch Speicherplatz zu beantragen delete:

Die Verwendung von Neu und Löschen

Im Gegensatz zu malloc und free sind new und delete eher Operatoren als Funktionen .

Wenn Sie „new“ und „delete“ verwenden, um Leerzeichen zu beantragen:
Verwenden Sie für ein einzelnes Element, new 类型;um ein Leerzeichen eines bestimmten Typs zu beantragen, und der Wert des Ausdrucks ist ein Zeiger auf dieses Leerzeichen. Sie können nach dem Typ Klammern verwenden, um den Wert dieses Typs zu initialisieren new 类型(初始值);;
entsprechend müssen Sie delete 指针;das Formular verwenden, um den Platz dieses einzelnen Elements freizugeben.

Verwenden Sie für kontinuierliche Elemente, new 类型[num];um einen kontinuierlichen Raum mit num-Typen zu beantragen, und der Wert des Ausdrucks ist die Adresse dieses Raums. Sie können {} nach [num] verwenden, um diesen Raum zu initialisieren: new 类型[num]{};;
Dementsprechend müssen Sie delete[] 指针;das Formular verwenden, um den Raum dieses fortlaufenden Elements freizugeben.

eingebauter Typ

Gemäß den oben eingeführten Regeln stehen für den dynamischen Anwendungsraum des integrierten Typs die folgenden Codes zur Verfügung:

int main()
{
    
    

	int* p1 = new int;  
	//动态开辟一块int的空间,不初始化
	int* p2 = new int(10);  
	//动态开辟一块int的空间,初始化为10
	int* p3 = new int[10];  
	//动态开辟一块10个int的空间,不初始化
	int* p4 = new int[10]{
    
     1,2,3,4,5,6,7,8,9,0 }; 
	//动态开辟一块i10个int的空间,初始化为1,2,3,4,5,6,7,8,9,0

	delete p1;
	delete p2;
	//释放单个元素空间用delete
	delete[] p3;
	delete[] p4;
	//释放连续空间需使用delete[]

	return 0;
}

Wir können die Werte in dem von jedem Teil beantragten Bereich durch Debuggen anzeigen:

Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Es ist zu beachten, dass newund delete, new []und delete[]nicht gemischt werden können. Obwohl es bei der dynamischen Anwendung für integrierte Typen keine Probleme gibt, stürzt das Programm bei benutzerdefinierten Typen ab.

benutzerdefinierter Typ

Bei integrierten Typen kann die Verwendung von malloc und free unsere Anforderungen kaum erfüllen. Bei benutzerdefinierten Typen wie Klassentypen müssen wir jedoch Klassenobjekte initialisieren, wenn wir Speicherplatz beantragen, und malloc kann unsere Anforderungen offensichtlich nicht erfüllen.

Nachdem new dynamisch Speicherplatz beantragt hat, wird auch der Standardkonstruktor aufgerufen. Mit delete wird der dynamisch angewendete Speicherplatz nach Aufruf des Destruktors freigegeben.
Hier müssen Sie besonders auf den Unterschied zwischen dem Raum von Klassenobjekten und dem Ressourcenraum in Klassenobjekten achten :

class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		_date = new char[_a + 1] {
    
    0};
		cout << "A(int a = 0)" << endl; //构造函数中打印
	}
	~A()
	{
    
    
		delete[] _date;
		_a = 0;
		cout << "~A()" << endl;  //析构函数中打印
	}
private:
	int _a;
	char* _date;
};

Diese Klasse A hat beispielsweise zwei Mitgliedsvariablen intund char*belegt 8 Bytes. Diese 8 Bytes sind der Raum des Klassenobjekts. Dieser Raum kann sich je nach Benutzer im Stapelbereich befinden oder dynamisch im Heap-Bereich angewendet werden; er
zeigt char*jedoch zu einem kontinuierlichen Raum. Die Größe dieses Raumes ist ungewiss. Sie wird im Konstruktor dynamisch angewendet, wenn das Klassenobjekt instanziiert wird, was vom Benutzer der Klasse nicht geändert werden kann. Dieser dynamisch geöffnete Raum ist die Ressource der Klasse, die nur im Konstruktor angewendet und im Destruktor freigegeben werden kann. Aus diesem Grund kann malloc unseren dynamischen Anwendungsbereich für benutzerdefinierte Typen nicht ausfüllen.

Fügen Sie hier eine Bildbeschreibung ein

Für den neuen benutzerdefinierten Typ stimmt die Verwendung mit dem integrierten Typ überein:
Wenn new zur Anwendung auf ein einzelnes Objekt verwendet wird, wird der Konstruktor einmal aufgerufen, wenn er auf num aufeinanderfolgende Objekte angewendet wird, wird der Konstruktor num mal aufgerufen; delete ist der Dasselbe:

int main()
{
    
    
	A* pa1 = new A;
	//动态开辟一个对象,调用默认构造初始化
	A* pa2 = new A(5);
	//动态开辟一个对象,传参给构造函数初始化
	A* pa3 = new A[5];
	//动态开辟一块连续的类对象空间,全部调用默认构造初始化
	A* pa4 = new A[5]{
    
     1,2,3,4,5 };
	//动态开辟一块连续的类对象空间,分别传参初始化

	delete pa1;
	delete pa2;
	//释放单个元素空间用delete
	delete[] pa3;
	delete[] pa4;
	//释放连续空间需使用delete[] !!!

	return 0;
}

Wir können den Status der dynamischen Anwendung durch Debuggen überprüfen:
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
Insgesamt werden 1+1+5+5=12 Konstruktoren und 12 Destruktoren aufgerufen:
Fügen Sie hier eine Bildbeschreibung ein

Das Realisierungsprinzip von Neu und Löschen

eingebauter Typ

Wenn Sie sich für einen integrierten Speicherplatztyp bewerben, sind new und malloc, delete und free grundsätzlich ähnlich. newDie Anwendung und die Freigabe gelten jedoch deletefür den Speicherplatz eines einzelnen Elements new []und delete[]die Anwendung für den fortlaufenden Speicherplatz. Wenn der Anwendungsbereich fehlschlägt, wird neweine Ausnahme ausgelöst und mallocNULL zurückgegeben

Es ist zu beachten, dass C++ beim dynamischen Anwenden oder Freigeben von Speicherplatz eher dazu neigt, eine Ausnahme auszulösen, um die Ursache des Fehlers widerzuspiegeln, wenn die Anwendung oder Freigabe fehlschlägt. Dieses Verhalten beim Auslösen einer Ausnahme wird in zwei Funktionen implementiert operator new. Durch Disassemblierung können wir auch überprüfen, ob beim Erstellen eines neuen Raums die Funktion „Neu“ des Operators tatsächlich aufgerufen wird, und wenn der Löschvorgang abgeschlossen ist, wird tatsächlich die Funktion „Löschen“ des Operators aufgerufen: Beim Anwenden und Freigeben von kontinuierlichem Raum wird natürlich die Funktion „und verwendet wird genannt. Diese beiden Funktionen werden jedoch durch den Aufruf mehrerer und implementiert .operator delete

Fügen Sie hier eine Bildbeschreibung ein
Fügen Sie hier eine Bildbeschreibung ein
operator new[]operator delete[]operator newoperator delete

Verständnis der Operator-Neu- und Operator-Löschfunktionen

Wir können einen kurzen Blick auf die operator newUND- operator deleteFunktion werfen:

new und delete sind Operatoren, mit denen Benutzer dynamischen Speicher anwenden und freigeben können. Operator new und Operator delete sind globale Funktionen, die vom System bereitgestellt werden. new ruft die neue globale Funktion des Operators auf der untersten Ebene auf, um Speicherplatz zu beantragen, und delete verwendet den Operator delete global Funktion auf der untersten Ebene, um Platz freizugeben .

Tatsächlich wird auch der Anwendungsraum operator newübergebenmalloc . Wenn der malloc-Anwendungsraum erfolgreich ist, wird er direkt zurückgegeben. Andernfalls werden die vom Benutzer bereitgestellten Gegenmaßnahmen für unzureichenden Speicherplatz implementiert. Wenn der Benutzer diese Maßnahme bereitstellt, wird die Anwendung fortgesetzt. andernfalls wird eine Ausnahme ausgelöst. operator deleteLetztendlich geht es darum free, Speicherplatz freizugeben .

benutzerdefinierter Typ

  1. Das Prinzip von new
    Rufen Sie operator newdie Funktion auf, um Speicherplatz zu beantragen, und führen Sie dann den Konstruktor für den angewendeten Speicherplatz aus, um die Konstruktion des Objekts abzuschließen.

  2. Das Prinzip des Löschens
    : Führt den Destruktor für den Speicherplatz aus, schließt die Bereinigung der Ressourcen im Objekt ab und ruft dann operator deletedie Funktion auf, um den Speicherplatz des Objekts freizugeben

  3. Das Prinzip von new T[num]
    ruft operator new[]die Funktion auf, ruft tatsächlich die Funktion im Operator new[] auf, operator newum die Anwendung von num Objekträumen abzuschließen, und führt den Konstruktor num mal auf dem angewendeten Raum aus

  4. Das Prinzip von delete[]
    : Führen Sie num-Destruktoren im freigegebenen Objektbereich aus, schließen Sie die Bereinigung der Ressourcen in num-Objekten ab und rufen Sie dann den operator delete[]Freigabebereich auf, der tatsächlich im Operator delete[] aufgerufen wird, operator deleteum den Speicherplatz freizugeben

neu positionieren

Beim Suchen nach „new“ kann ein Teil des dynamischen Raums verwendet werden, der zum Aufrufen des Konstruktors zum Initialisieren des Klassenobjekts angewendet wurde

Das Auffinden von Neuen wird normalerweise in Verbindung mit dem Speicherpool verwendet (der Speicherpool ist ein Speicherplatz, der im Voraus beantragt wurde). Durch die vorherige Beantragung eines Teils des Speicherplatzes kann die durch häufige Erweiterung verursachte Effizienzminderung vermieden werden, die durch häufigen Anwendungsbereich verursacht wird ). Der Speicherplatz im Speicherpool dient nur der Anwendung, nicht der Initialisierung. Wir können die Initialisierung erreichen, indem wir neue finden:

Das Format für die Verwendung von „Positioning New“ lautet: new (要初始化的空间的指针) 类型;Es ist zu beachten, dass Parameter übergeben werden müssen, wenn der zu initialisierende Klassentyp keinen Standardkonstruktor hat. new (要初始化的空间的指针) 类型(构造函数参数列表);Wenn
die Ressourcen des durch Positionieren von New initialisierten Klassenobjekts freigegeben werden, ist dies erforderlich Rufen Sie das Klassenobjekt explizit auf. Der Destruktor soll die Zuordnung aufheben:

class A
{
    
    
public:
	A(int a = 0)
		:_a(a)
	{
    
    
		_date = new char[_a + 1] {
    
    0};
		cout << "A(int a = 0)" << endl; //构造函数中打印
	}
	~A()
	{
    
    
		delete[] _date;
		_a = 0;
		cout << "~A()" << endl;  //析构函数中打印
	}
private:
	int _a;
	char* _date;
};

int main()
{
    
    
	A* ptr = (A*)malloc(1000);
	//创建1000个字节的空间
	new(ptr)A(5);
	//用上面申请的空间初始化一个A对象
	ptr->~A();
	//释放上面定位new初始化的对象的资源
	free(ptr);
	//释放malloc出的空间
	return 0;
}

Zu beachten ist der Unterschied zwischen Klassenraum und Klassenressourcenraum : Hier gilt malloc nur für einen Teil des Raums, und die folgende Neuerung besteht darin, den Raum in malloc zu initialisieren. Dieses Initialisierungsverhalten umfasst die Beantragung von Klassenressourcen, die nicht dazu gehören um malloc aus dem Raum zu entfernen;
delete gibt die Ressourcen der Klasse frei und free verliert den Raum aus malloc.

Der Unterschied zwischen new&delete und malloc&free

  1. malloc und free sind Funktionen; new und delete sind Operatoren

  2. Der von malloc angeforderte Speicherplatz wird nicht initialisiert; neuer kann initialisiert werden

  3. Wenn malloc Speicherplatz beantragt, müssen Sie die Größe des Speicherplatzes manuell berechnen und weitergeben. Auf new muss nur der Typ des Speicherplatzes folgen. Wenn mehrere Objekte vorhanden sind, geben Sie die Anzahl der Objekte in [num] an.

  4. Der Rückgabewert von malloc void*muss bei Verwendung erzwungen werden; new benötigt ihn nicht, da die Art des Leerzeichens nach new angegeben wird

  5. Wenn malloc keinen Speicherplatz beantragt, gibt es NULL zurück, daher muss es bei der Verwendung als leer beurteilt werden; new benötigt es nicht, aber new muss Ausnahmen abfangen

  6. Bei der Beantragung eines benutzerdefinierten Objekttyps öffnet malloc/free nur Speicherplatz und ruft weder den Konstruktor noch den Destruktor auf, während new den Konstruktor aufruft, um die Initialisierung des Objekts nach der Beantragung von Speicherplatz abzuschließen, und delete den Konstruktor aufruft Destruktor vor der Freigabe des Speicherplatzes Schließen Sie die Bereinigung der Ressourcen im Speicherplatz ab

Zusammenfassen

Zu diesem Zeitpunkt ist die Einführung der C/C++-Speicherverwaltung abgeschlossen.
Ich glaube, Sie haben nicht nur die Verwendung von new und delete in C++ gelernt, sondern auch Ihr Verständnis der Speicherverwaltung vertieft.

Wenn Sie der Meinung sind, dass ich einen bestimmten Teil nicht klar dargelegt habe oder dass bei einem bestimmten Teil ein Problem vorliegt, können Sie dies gerne im Kommentarbereich ansprechen

Wenn dieser Artikel für Sie hilfreich ist, hoffe ich, dass er mit einem Klick verknüpft wird

Ich hoffe, gemeinsam mit Ihnen Fortschritte zu machen

Ich denke du magst

Origin blog.csdn.net/weixin_73450183/article/details/131139176
Empfohlen
Rangfolge