Suche…


Syntax

  • : :( opt ) new ( Ausdrucksliste ) ( opt ) new-type-id new-initializer ( opt )
  • : :( opt ) new ( Ausdrucksliste ) ( opt ) ( Typ-ID ) new-initializer ( opt )
  • : :( ( opt ) löscht den Cast-Ausdruck
  • : :( ( opt ) delete [] Cast-Ausdruck
  • std :: unique_ptr < Typ-ID > Variablenname (neue Typ-ID ( Opt )); // C ++ 11
  • std :: shared_ptr < Typ-ID > Variablenname (neue Typ-ID ( Opt )); // C ++ 11
  • std :: shared_ptr < typ-id > var_name = std :: make_shared < typ-id > ( opt ); // C ++ 11
  • std :: unique_ptr < typ-id > var_name = std :: make_unique < typ-id > ( opt ); // C ++ 14

Bemerkungen

Ein Lead :: zwingt den New- oder Delete-Operator dazu, im globalen Gültigkeitsbereich nachzuschlagen, wobei alle überlasteten klassenspezifischen New- oder Delete-Operatoren überschrieben werden.

Die optionalen Argumente nach dem new Schlüsselwort werden normalerweise verwendet, um Platzierung neu aufzurufen, können jedoch auch verwendet werden, um zusätzliche Informationen an den Zuweiser zu übergeben, z. B. ein Tag, das anfordert, dass Speicher aus einem ausgewählten Pool zugewiesen wird.

Der zugewiesene Typ wird normalerweise explizit angegeben, z. B. new Foo , kann aber auch als auto (seit C ++ 11) oder decltype(auto) (seit C ++ 14) geschrieben werden, um ihn vom Initialisierer abzuleiten.

Die Initialisierung des zugeordneten Objekts erfolgt nach den gleichen Regeln wie die Initialisierung lokaler Variablen. Insbesondere wird das Objekt standardmäßig initialisiert, wenn der Initialisierer nicht angegeben wird, und wenn ein Skalar-Typ oder ein Array mit einem Skalar-Typ dynamisch zugewiesen wird, kann nicht garantiert werden, dass der Speicher auf Null gesetzt wird.

Ein mit einem neuen Ausdruck erstelltes Array-Objekt muss mit delete[] , unabhängig davon, ob der neue Ausdruck mit [] oder nicht. Zum Beispiel:

using IA = int[4];
int* pIA = new IA;
delete[] pIA;  // right
// delete pIA;  // wrong

Stapel

Der Stack ist ein kleiner Speicherbereich, in den temporäre Werte während der Ausführung eingefügt werden. Die Zuordnung von Daten in den Stapel ist im Vergleich zur Heap-Zuordnung sehr schnell, da der gesamte Speicher bereits für diesen Zweck zugewiesen wurde.

int main() {
    int a = 0; //Stored on the stack
    return a;
}

Der Stack wird benannt, weil Ketten von Funktionsaufrufen ihren temporären Speicher übereinander "stapeln", wobei jeder einen separaten kleinen Speicherbereich verwendet.

float bar() {
    //f will be placed on the stack after anything else
    float f = 2;
    return f;
}

double foo() {
    //d will be placed just after anything within main()
    double d = bar();
    return d;
}

int main() {
    //The stack has no user variables stored in it until foo() is called
    return (int)foo();
}

Auf dem Stack gespeicherte Daten sind nur gültig, solange der Bereich, der die Variable zugewiesen hat, noch aktiv ist.

int* pA = nullptr;

void foo() {
    int b = *pA;
    pA = &b;
}

int main() {
    int a = 5;
    pA = &a;
    foo();
    //Undefined behavior, the value pointed to by pA is no longer in scope
    a = *pA;
}

Freier Speicher (Heap, dynamische Zuordnung ...)

Der Begriff "Heap" ist ein allgemeiner Berechnungsausdruck, der einen Speicherbereich bedeutet, aus dem Teile zugewiesen und freigegeben werden können, unabhängig von dem vom Stapel bereitgestellten Speicher.

In C++ der Standard diesen Bereich als Free Store, was als genauerer Begriff angesehen wird.

Vom Free Store zugewiesene Speicherbereiche leben möglicherweise länger als der ursprüngliche Umfang, in dem sie zugewiesen wurden. Daten, die zu groß sind, um auf dem Stack gespeichert zu werden, können auch aus dem Free Store zugewiesen werden.

Rohspeicher kann durch die neuen und Löschschlüsselwörter zugewiesen und freigegeben werden.

float *foo = nullptr;
{
    *foo = new float; // Allocates memory for a float
    float bar;              // Stack allocated 
} // End lifetime of bar, while foo still alive

delete foo;          // Deletes the memory for the float at pF, invalidating the pointer
foo = nullptr;       // Setting the pointer to nullptr after delete is often considered good practice

Es ist auch möglich, Arrays fester Größe mit new und delete mit einer etwas anderen Syntax zuzuordnen. Die Arrayzuweisung ist nicht kompatibel mit der Nicht-Arrayzuordnung. Das Mischen der beiden führt zu Heap-Beschädigungen. Durch die Zuweisung eines Arrays wird auch Speicher zugewiesen, um die Größe des Arrays für eine spätere Löschung in einer implementierungsdefinierten Weise zu verfolgen.

// Allocates memory for an array of 256 ints
int *foo = new int[256];
// Deletes an array of 256 ints at foo
delete[] foo;

Wenn Sie new und delete statt malloc und free verwenden , werden Konstruktor und Destruktor ausgeführt (ähnlich wie bei stapelbasierten Objekten). Deshalb werden Neu und Löschen gegenüber Malloc und kostenlos bevorzugt.

struct ComplexType {
    int a = 0;

    ComplexType() { std::cout << "Ctor" << std::endl; }
    ~ComplexType() { std::cout << "Dtor" << std::endl; }
};

// Allocates memory for a ComplexType, and calls its constructor
ComplexType *foo = new ComplexType();
//Calls the destructor for ComplexType() and deletes memory for a Complextype at pC
delete foo;
C ++ 11

Ab C ++ 11 wird die Verwendung von intelligenten Zeigern für die Angabe des Eigentums empfohlen.

C ++ 14

C ++ 14 fügte std::make_unique zur STL hinzu und änderte die Empfehlung, um std::make_unique oder std::make_shared zu std::make_shared anstatt nacktes new und delete zu verwenden .

Platzierung neu

Es gibt Situationen, in denen wir uns beim Zuweisen von Speicher nicht auf Free Store verlassen möchten und benutzerdefinierte Speicherzuordnungen mit new möchten.

Für diese Situationen können wir Placement New , wo wir dem 'new'-Operator mitteilen können, dass er Speicherplatz von einem zuvor zugewiesenen Speicherplatz zuweisen soll

Zum Beispiel

int a4byteInteger;

char *a4byteChar = new (&a4byteInteger) char[4];

In diesem Beispiel ist der Speicher, auf den a4byteChar zeigt, 4 Byte, die über die Integer-Variable a4byteInteger dem 'Stack' a4byteInteger .

Der Vorteil dieser Art der Speicherzuordnung ist die Tatsache, dass Programmierer die Zuweisung steuern. Da im a4byteInteger Beispiel a4byteInteger auf Stack zugewiesen wird, müssen Sie nicht explizit "delete a4byteChar" aufrufen.

Dasselbe Verhalten kann auch für dynamisch zugewiesenen Speicher erreicht werden. Zum Beispiel

int *a8byteDynamicInteger = new int[2];

char *a8byteChar = new (a8byteDynamicInteger) char[8];

In diesem Fall verweist der Speicherzeiger von a8byteChar auf den dynamischen Speicher, der von a8byteDynamicInteger zugewiesen wird. In diesem Fall müssen Sie jedoch delete a8byteDynamicInteger explizit aufrufen, um den Speicher freizugeben

Ein weiteres Beispiel für die C ++ - Klasse

struct ComplexType {
    int a;

    ComplexType() : a(0) {}
    ~ComplexType() {}
};

int main() {
    char* dynArray = new char[256];

    //Calls ComplexType's constructor to initialize memory as a ComplexType
    new((void*)dynArray) ComplexType();

    //Clean up memory once we're done
    reinterpret_cast<ComplexType*>(dynArray)->~ComplexType();
    delete[] dynArray;

    //Stack memory can also be used with placement new
    alignas(ComplexType) char localArray[256]; //alignas() available since C++11

    new((void*)localArray) ComplexType();

    //Only need to call the destructor for stack memory
    reinterpret_cast<ComplexType*>(localArray)->~ComplexType();

    return 0;
}


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow