Partager via


new, opérateur (C++)

Tente d’allouer et d’initialiser un objet ou un tableau d’objets d’un type d’espace réservé ou spécifié, et retourne un pointeur à l’objet (ou à l’objet initial du tableau) correctement typé et non égal à zéro.

Syntaxe

new-expression:
::opt new new-placementopt new-type-id new-initializeropt
::opt new new-placementopt ( type-id ) new-initializeropt

new-placement:
( expression-list )

new-type-id:
type-specifier-seq new-declaratoropt

new-declarator:
ptr-operator new-declaratoropt
noptr-new-declarator

noptr-new-declarator:
[ expression ] attribute-specifier-seqopt
noptr-new-declarator [ constant-expression ] attribute-specifier-seqopt

new-initializer:
( expression-listopt )
braced-init-list

Notes

En cas d’échec, new retourne zéro ou lève une exception. Pour plus d’informations, consultez Opérateurs new et delete. Vous pouvez modifier ce comportement par défaut en écrivant une routine personnalisée de gestion des exceptions et en appelant la fonction de bibliothèque du runtime _set_new_handler avec le nom de fonction comme argument.

Pour plus d’informations sur la façon de créer un objet sur le tas managé en C++/CLI et C++/CX, consultez gcnew.

Remarque

Microsoft C++ Component Extensions (C++/CX) fournit la prise en charge du mot clé new pour ajouter des entrées d’emplacement vtable. Pour plus d’informations, consultez new (nouvel emplacement dans vtable)

Lorsque new est utilisé pour allouer la mémoire à un objet de classe C++, le constructeur de l’objet est appelé après que la mémoire est allouée.

Utilisez l’opérateur delete pour libérer la mémoire allouée par l’opérateur new. Utilisez l’opérateur delete[] pour supprimer un tableau alloué par l’opérateur new.

L'exemple suivant alloue, puis libère un tableau de caractères à deux dimensions de taille dim par 10. Lors de l’allocation d’un tableau multidimensionnel, toutes les dimensions sauf la première doivent être des expressions constantes évaluées comme valeurs positives. La dimension du tableau la plus à gauche peut être toute expression évaluée comme valeur positive Lors de l’allocation d’un tableau à l’aide de l’opérateur new, la première dimension peut être zéro. L’opérateur new retourne un seul pointeur.

char (*pchar)[10] = new char[dim][10];
delete [] pchar;

type-id ne peut pas contenir const, volatile, des déclarations de classe ou des déclarations d’énumération. L’expression suivante est mal formée :

volatile char *vch = new volatile char[20];

L’opérateur new n’alloue pas de types référence, car il ne s’agit pas d’objets.

L’opérateur new ne peut pas être utilisé pour allouer une fonction. En revanche, il peut être utilisé pour allouer des pointeurs vers des fonctions. L'exemple suivant alloue, puis libère un tableau de sept pointeurs vers des fonctions qui retournent des entiers.

int (**p) () = new (int (*[7]) ());
delete p;

Si vous utilisez l’opérateur new sans argument supplémentaire, et que vous compilez avec l’option /GX, /EHa, ou /EHs, le compilateur génère du code pour appeler l’opérateur delete si le constructeur lève une exception.

La liste suivante décrit les éléments de grammaire de new :

new-placement
Permet de transmettre des arguments supplémentaires si vous surchargez new.

type-id
Spécifie le type à allouer ; il peut s’agir d’un type intégré ou d’un type défini par l’utilisateur. Si la spécification de type est compliquée, elle peut être placée entre parenthèses pour forcer l'ordre de liaison. Le type peut être un espace réservé (auto) dont le type est déterminé par le compilateur.

new-initializer
Fournit une valeur pour l'objet initialisé. Les initialiseurs ne peuvent pas être spécifiés pour des tableaux. L’opérateur new crée des tableaux d’objets uniquement si la classe a un constructeur par défaut.

noptr-new-declarator
Spécifie les limites d’un tableau. Lors de l’allocation d’un tableau multidimensionnel, toutes les dimensions sauf la première doivent être des expressions constantes évaluées comme valeurs positives convertibles en std::size_t. La dimension du tableau la plus à gauche peut être toute expression évaluée comme valeur positive attribute-specifier-seq s’applique au type de tableau associé.

Exemple : Allouer et libérer un tableau de caractères

L'exemple de code suivant alloue un tableau de caractères et un objet de classe CName, puis les libère.

// expre_new_Operator.cpp
// compile with: /EHsc
#include <string.h>

class CName {
public:
   enum {
      sizeOfBuffer = 256
   };

   char m_szFirst[sizeOfBuffer];
   char m_szLast[sizeOfBuffer];

public:
   void SetName(char* pszFirst, char* pszLast) {
     strcpy_s(m_szFirst, sizeOfBuffer, pszFirst);
     strcpy_s(m_szLast, sizeOfBuffer, pszLast);
   }

};

int main() {
   // Allocate memory for the array
   char* pCharArray = new char[CName::sizeOfBuffer];
   strcpy_s(pCharArray, CName::sizeOfBuffer, "Array of characters");

   // Deallocate memory for the array
   delete [] pCharArray;
   pCharArray = NULL;

   // Allocate memory for the object
   CName* pName = new CName;
   pName->SetName("Firstname", "Lastname");

   // Deallocate memory for the object
   delete pName;
   pName = NULL;
}

Exemple : Opérateur new

Si vous utilisez la forme de placement de l’opérateur new (la forme avec davantage d’arguments que la taille), le compilateur ne prend pas en charge une forme de placement de l’opérateur delete si le constructeur lève une exception. Par exemple :

// expre_new_Operator2.cpp
// C2660 expected
class A {
public:
   A(int) { throw "Fail!"; }
};
void F(void) {
   try {
      // heap memory pointed to by pa1 will be deallocated
      // by calling ::operator delete(void*).
      A* pa1 = new A(10);
   } catch (...) {
   }
   try {
      // This will call ::operator new(size_t, char*, int).
      // When A::A(int) does a throw, we should call
      // ::operator delete(void*, char*, int) to deallocate
      // the memory pointed to by pa2.  Since
      // ::operator delete(void*, char*, int) has not been implemented,
      // memory will be leaked when the deallocation can't occur.

      A* pa2 = new(__FILE__, __LINE__) A(20);
   } catch (...) {
   }
}

int main() {
   A a;
}

Initialisation des objets alloués avec new

Un champ new-initializer facultatif est inclus dans la grammaire pour l’opérateur new. Ce champ permet aux nouveaux objets d’être initialisés avec des constructeurs définis par l’utilisateur. Pour plus d’informations sur la façon dont l’initialisation est effectuée, consultez Initialiseurs. L’exemple suivant montre comment utiliser une expression d’initialisation avec l’opérateur new :

// expre_Initializing_Objects_Allocated_with_new.cpp
class Acct
{
public:
    // Define default constructor and a constructor that accepts
    //  an initial balance.
    Acct() { balance = 0.0; }
    Acct( double init_balance ) { balance = init_balance; }
private:
    double balance;
};

int main()
{
    Acct *CheckingAcct = new Acct;
    Acct *SavingsAcct = new Acct ( 34.98 );
    double *HowMuch = new double { 43.0 };
    // ...
}

Dans cet exemple, l’objet CheckingAcct est alloué à l’aide de l’opérateur new, mais aucune initialisation par défaut n’est spécifiée. Par conséquent, le constructeur par défaut pour la classe, Acct(), est appelé. Ensuite, l’objet SavingsAcct est alloué de la même façon, mais il est initialisé explicitement à 34,98. Comme 34,98 est du type double, le constructeur qui prend un argument de ce type est appelé pour traiter l’initialisation. Pour finir, le type sans classe HowMuch est initialisé à 43,0.

Si un objet est d’un type classe et que cette classe a des constructeurs (comme dans l’exemple précédent), l’objet peut être initialisé par l’opérateur new uniquement si l’une des conditions suivantes est remplie :

  • Les arguments fournis dans l’initialiseur correspondent à ceux d’un constructeur.

  • La classe possède un constructeur par défaut (un constructeur pouvant être appelé sans argument).

L’initialisation explicite par élément ne peut pas être effectuée en allouant des tableaux à l’aide de l’opérateur new ; seul le constructeur par défaut, s’il est présent, est appelé. Pour plus d’informations, consultez Arguments par défaut.

Si l’allocation de mémoire échoue (operator new retourne la valeur 0), aucune initialisation n’est effectuée. Ce comportement empêche les tentatives d’initialisation de données qui n’existent pas.

Comme avec les appels de fonction, l’ordre dans lequel les expressions initialisées sont évaluées n’est pas défini. En outre, vous ne devez pas vous attendre à ce que ces expressions soient complètement évaluées avant que l’allocation de mémoire ait eu lieu. Si l’allocation de mémoire échoue et que l’opérateur new retourne zéro, certaines expressions dans l’initialiseur risquent de ne pas être entièrement évaluées.

Durée de vie des objets alloués avec new

Les objets alloués avec l’opérateur new ne sont pas détruits lorsque vous quittez l’étendue dans laquelle ils sont définis. Comme l’opérateur new retourne un pointeur désignant les objets qu’il alloue, le programme doit définir un pointeur avec une étendue appropriée pour accéder à ces objets et les supprimer. Par exemple :

// expre_Lifetime_of_Objects_Allocated_with_new.cpp
// C2541 expected
int main()
{
    // Use new operator to allocate an array of 20 characters.
    char *AnArray = new char[20];

    for( int i = 0; i < 20; ++i )
    {
        // On the first iteration of the loop, allocate
        //  another array of 20 characters.
        if( i == 0 )
        {
            char *AnotherArray = new char[20];
        }
    }

    delete [] AnotherArray; // Error: pointer out of scope.
    delete [] AnArray;      // OK: pointer still in scope.
}

Une fois que le pointeur AnotherArray sort de la portée de l'exemple, l'objet ne peut plus être supprimé.

Comment new fonctionne

new-expression (l’expression contenant l’opérateur new) effectue trois opérations :

  • Localise et réserve le stockage pour les objets à allouer. Lorsque cette phase est terminée, la quantité correcte d’espace de stockage est allouée, mais ce n’est pas encore un objet.

  • Initialise les objets. Une fois que l'initialisation est terminée, les informations disponibles sont suffisantes pour que le stockage alloué soit un objet.

  • Retourne un pointeur vers les objets d’un type pointeur dérivé de new-type-id ou de type-id. Le programme utilise ce pointeur pour accéder au nouvel objet alloué.

L’opérateur new appelle la fonction operator new. Pour les tableaux de tout type et pour les objets qui ne sont pas de type class, struct ou union, une fonction globale, ::operator new, est appelée pour allouer le stockage. Les objets de type de classe peuvent définir leur propre fonction membre statique operator new pour chaque classe.

Lorsque le compilateur rencontre l’opérateur new pour allouer un objet de type T, il émet un appel à T::operator new( sizeof(T) ) ou, si aucun operator new défini par l’utilisateur n’est défini, ::operator new( sizeof(T) ). C’est ainsi que l’opérateur new peut allouer la quantité correcte de mémoire pour l’objet.

Remarque

L’argument de operator new est de type std::size_t. Ce type est défini dans <direct.h>, <malloc.h>, <memory.h>, <search.h>, <stddef.h>, <stdio.h>, <stdlib.h>, <string.h> et <time.h>.

Une option dans la grammaire permet la spécification de new-placement (consultez la grammaire correspondant à l’opérateur new). Le paramètre new-placement peut être utilisé uniquement pour les implémentations définies par l’utilisateur de operator new ; il permet de transmettre des informations supplémentaires à operator new. Une expression avec un champ new-placement tel que T *TObject = new ( 0x0040 ) T; est traduite en T *TObject = T::operator new( sizeof( T ), 0x0040 ); si la classe T comporte un opérateur membre operator new ; autrement, elle est traduite en T *TObject = ::operator new( sizeof( T ), 0x0040 );.

L’objectif initial du champ new-placement est de permettre l’allocation d’objets dépendants du matériel à des adresses spécifiées par l’utilisateur.

Remarque

Bien que l’exemple précédent indique un seul argument dans le champ new-placement, il n’existe aucune restriction quant au nombre d’arguments supplémentaires pouvant être transmis à operator new de cette façon.

Même lorsque operator new a été défini pour un type classe T, vous pouvez utiliser explicitement l’opérateur new global, comme dans cet exemple :

T *TObject = ::new TObject;

L’opérateur de résolution d’étendue (::) force l’utilisation de l’opérateur new global.

Voir aussi

Expressions avec des opérateurs unaires
Mots clés
Opérateurs new et delete