Eine dynamische Zuordnung ist nur erforderlich, wenn die Lebensdauer des Objekts von dem Bereich abweichen soll, in dem es erstellt wird (dies gilt auch, um den Bereich kleiner als größer zu machen) und Sie einen bestimmten Grund haben, warum das Speichern nach Wert dies nicht tut Arbeit.
Zum Beispiel:
std::vector<int> *createVector(); // Bad
std::vector<int> createVector(); // Good
auto v = new std::vector<int>(); // Bad
auto result = calculate(/*optional output = */ v);
auto v = std::vector<int>(); // Good
auto result = calculate(/*optional output = */ &v);
Ab C ++ 11 müssen wir uns std::unique_ptr
mit dem zugewiesenen Speicher befassen, der den Besitz des zugewiesenen Speichers enthält. std::shared_ptr
wurde erstellt, wenn Sie das Eigentum teilen müssen. (Sie benötigen dies weniger als Sie in einem guten Programm erwarten würden)
Das Erstellen einer Instanz wird ganz einfach:
auto instance = std::make_unique<Class>(/*args*/); // C++14
auto instance = std::make_unique<Class>(new Class(/*args*/)); // C++11
auto instance = std::make_unique<Class[]>(42); // C++14
auto instance = std::make_unique<Class[]>(new Class[](42)); // C++11
C ++ 17 fügt außerdem hinzu, std::optional
wodurch verhindert werden kann, dass Speicherzuordnungen erforderlich sind
auto optInstance = std::optional<Class>{};
if (condition)
optInstance = Class{};
Sobald 'Instanz' den Gültigkeitsbereich verlässt, wird der Speicher bereinigt. Die Übertragung des Eigentums ist auch einfach:
auto vector = std::vector<std::unique_ptr<Interface>>{};
auto instance = std::make_unique<Class>();
vector.push_back(std::move(instance)); // std::move -> transfer (most of the time)
Wann brauchen Sie noch new
? Fast nie ab C ++ 11. Die meisten davon verwenden Sie, std::make_unique
bis Sie zu einem Punkt gelangen, an dem Sie auf eine API stoßen, die den Besitz über Rohzeiger überträgt.
auto instance = std::make_unique<Class>();
legacyFunction(instance.release()); // Ownership being transferred
auto instance = std::unique_ptr<Class>{legacyFunction()}; // Ownership being captured in unique_ptr
In C ++ 98/03 müssen Sie die manuelle Speicherverwaltung durchführen. In diesem Fall versuchen Sie, ein Upgrade auf eine neuere Version des Standards durchzuführen. Wenn Sie nicht weiterkommen:
auto instance = new Class(); // Allocate memory
delete instance; // Deallocate
auto instances = new Class[42](); // Allocate memory
delete[] instances; // Deallocate
Stellen Sie sicher, dass Sie den Besitz korrekt verfolgen, um keine Speicherlecks zu haben! Die Bewegungssemantik funktioniert auch noch nicht.
Wann brauchen wir Malloc in C ++? Der einzig gültige Grund wäre, Speicher zuzuweisen und ihn später durch Platzierung neu zu initialisieren.
auto instanceBlob = std::malloc(sizeof(Class)); // Allocate memory
auto instance = new(instanceBlob)Class{}; // Initialize via constructor
instance.~Class(); // Destroy via destructor
std::free(instanceBlob); // Deallocate the memory
Obwohl das oben Gesagte gültig ist, kann dies auch über einen neuen Operator erfolgen. std::vector
ist ein gutes Beispiel dafür.
Endlich haben wir noch den Elefanten im Raum : C
. Wenn Sie mit einer C-Bibliothek arbeiten müssen, in der Speicher im C ++ - Code zugewiesen und im C-Code freigegeben wird (oder umgekehrt), müssen Sie malloc / free verwenden.
Wenn Sie in diesem Fall sind, vergessen Sie virtuelle Funktionen, Elementfunktionen, Klassen ... Nur Strukturen mit PODs sind zulässig.
Einige Ausnahmen von den Regeln:
- Sie schreiben eine Standardbibliothek mit erweiterten Datenstrukturen, in denen malloc angemessen ist
- Sie müssen große Speichermengen zuweisen (In der Speicherkopie einer 10-GB-Datei?)
- Sie haben Werkzeuge, die Sie daran hindern, bestimmte Konstrukte zu verwenden
- Sie müssen einen unvollständigen Typ speichern