Recherche…


Syntaxe

  • : :( opt ) new ( liste-expression ) ( opt ) new-type-id new-initializer ( opt )
  • : :( opt ) new ( liste-expression ) ( opt ) ( type-id ) nouvel-initialiseur ( opt )
  • : :( opt ) supprimer l' expression-cast
  • : :( opt ) delete [] cast-expression
  • std :: unique_ptr < type-id > nom_variable (nouvel identificateur de type ( opt )); // C ++ 11
  • std :: shared_ptr < type-id > nom_variable (nouveau type-id ( opt )); // C ++ 11
  • std :: shared_ptr < id-type > nom_var = std :: make_shared < id-type > ( opt ); // C ++ 11
  • std :: unique_ptr < type-id > nom_var = std :: make_unique < type-id > ( opt ); // C ++ 14

Remarques

Un leader :: force l'opérateur new ou delete à rechercher dans une portée globale, en remplaçant tous les opérateurs surchargés ou nouveaux spécifiques à la classe.

Les arguments facultatifs qui suivent le new mot-clé sont généralement utilisés pour appeler le placement new , mais peuvent également être utilisés pour transmettre des informations supplémentaires à l'allocateur, par exemple une balise demandant que la mémoire soit allouée depuis un pool choisi.

Le type alloué est généralement explicitement spécifié, par exemple new Foo , mais peut aussi être écrit comme auto (depuis C ++ 11) ou decltype(auto) (depuis C ++ 14) pour le déduire de l'initialiseur.

L'initialisation de l'objet alloué se produit selon les mêmes règles que l'initialisation des variables locales. En particulier, l'objet sera initialisé par défaut si l'initialiseur est omis, et lors de l'allocation dynamique d'un type scalaire ou d'un tableau de type scalaire, rien ne garantit que la mémoire sera mise à zéro.

Un objet tableau créé par une nouvelle expression doit être détruit à l'aide de delete[] , que la nouvelle expression ait été écrite avec [] ou non. Par exemple:

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

Empiler

La pile est une petite région de mémoire dans laquelle des valeurs temporaires sont placées pendant l'exécution. L'allocation de données dans la pile est très rapide par rapport à l'allocation de tas car toute la mémoire a déjà été affectée à cette fin.

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

La pile est nommée parce que les chaînes d'appels de fonctions auront leur mémoire temporaire «empilée» l'une sur l'autre, chacune utilisant une petite section de mémoire distincte.

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();
}

Les données stockées sur la pile ne sont valides que tant que la portée à laquelle la variable est allouée est toujours active.

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;
}

Stockage gratuit (tas, allocation dynamique ...)

Le terme «tas» est un terme informatique général désignant une zone de mémoire à partir de laquelle des parties peuvent être allouées et désallouées indépendamment de la mémoire fournie par la pile .

En C++ la norme fait référence à cette zone en tant que magasin gratuit, ce qui est considéré comme un terme plus précis.

Les zones de mémoire allouées à partir du magasin gratuit peuvent vivre plus longtemps que la portée d'origine dans laquelle elles ont été allouées. Les données trop volumineuses pour être stockées sur la pile peuvent également être attribuées à partir du magasin gratuit .

La mémoire brute peut être allouée et libérée par le nouveau et supprimer les mots-clés.

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

Il est également possible d'allouer des tableaux de taille fixe avec new et delete , avec une syntaxe légèrement différente. L'attribution des tableaux n'est pas compatible avec l'allocation sans tableau, et le mélange des deux entraînera une corruption du tas. L'allocation d'un tableau alloue également de la mémoire pour suivre la taille du tableau en vue d'une suppression ultérieure, de manière définie par l'implémentation.

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

Si vous utilisez new et delete plutôt que malloc et free , le constructeur et le destructeur seront exécutés (similaire aux objets basés sur la pile). C'est pourquoi les nouveaux et les supprimer sont préférables à malloc et gratuits .

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

A partir de C ++ 11, l'utilisation de pointeurs intelligents est recommandée pour indiquer la propriété.

C ++ 14

C ++ 14 a ajouté std::make_unique à la STL, en modifiant la recommandation pour privilégier std::make_unique ou std::make_shared au lieu d'utiliser nue new et delete .

Nouveau placement

Il y a des situations où nous ne voulons pas compter sur Free Store pour allouer de la mémoire et nous voulons utiliser des allocations de mémoire personnalisées en utilisant new .

Pour ces situations, nous pouvons utiliser Placement New , où nous pouvons demander à un nouvel opérateur d’allouer de la mémoire à partir d’un emplacement de mémoire pré-alloué.

Par exemple

int a4byteInteger;

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

Dans cet exemple, la mémoire pointée par a4byteChar est de 4 octets alloués à 'stack' via la variable entière a4byteInteger .

L'avantage de ce type d'allocation de mémoire est le fait que les programmeurs contrôlent l'allocation. Dans l'exemple ci-dessus, comme a4byteInteger est alloué sur la pile, nous n'avons pas besoin d'appeler explicitement 'delete a4byteChar`.

Le même comportement peut être obtenu pour la mémoire allouée dynamique également. Par exemple

int *a8byteDynamicInteger = new int[2];

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

Dans ce cas, le pointeur de mémoire par a8byteChar fera référence à la mémoire dynamique allouée par a8byteDynamicInteger . Dans ce cas, cependant, nous devons appeler explicitement delete a8byteDynamicInteger pour libérer la mémoire

Un autre exemple pour la classe C ++

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
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow