Namespaces
Variants

operator new, operator new[]

De fr.cppreference.net
< cpp | memory | new
 
 
Bibliothèque des utilitaires
Support du langage
Support des types (types de base, RTTI)
Macros de test de fonctionnalités de la bibliothèque (C++20)
Utilitaires de programme
Fonctions variadiques
Support des coroutines (C++20)
Support des contrats (C++26)
Comparaison à trois voies
(C++20)
(C++20)(C++20)(C++20)    
(C++20)(C++20)(C++20)

Utilitaires généraux
Opérateurs relationnels (déprécié en C++20)
 
Bibliothèque de gestion de la mémoire
Allocateurs
Ressources mémoire
Stockage non initialisé (jusqu'à C++20*)
Support du ramasse-miettes (jusqu'à C++23)
 
 
Défini dans l'en-tête <new>
Fonctions d'allocation remplaçables
void* operator new  ( std::size_t count );
(1)
void* operator new[]( std::size_t count );
(2)
void* operator new  ( std::size_t count, std::align_val_t al );
(3) (depuis C++17)
void* operator new[]( std::size_t count, std::align_val_t al );
(4) (depuis C++17)
Fonctions d'allocation non lancinantes remplaçables
void* operator new  ( std::size_t count, const std::nothrow_t& tag );
(5) (noexcept depuis C++11)
void* operator new[]( std::size_t count, const std::nothrow_t& tag );
(6) (noexcept depuis C++11)
void* operator new  ( std::size_t count, std::align_val_t al,
                      const std::nothrow_t& tag ) noexcept;
(7) (depuis C++17)
void* operator new[]( std::size_t count, std::align_val_t al,
                      const std::nothrow_t& tag ) noexcept;
(8) (depuis C++17)
Fonctions d'allocation de placement sans allocation
void* operator new  ( std::size_t count, void* ptr );
(9) (noexcept depuis C++11)
(constexpr depuis C++26)
void* operator new[]( std::size_t count, void* ptr );
(10) (noexcept depuis C++11)
(constexpr depuis C++26)
Fonctions d'allocation de placement définies par l'utilisateur
void* operator new  ( std::size_t count, /* args... */ );
(11)
void* operator new[]( std::size_t count, /* args... */ );
(12)
void* operator new  ( std::size_t count,
                      std::align_val_t al, /* args... */ );
(13) (depuis C++17)
void* operator new[]( std::size_t count,
                      std::align_val_t al, /* args... */ );
(14) (depuis C++17)
Fonctions d'allocation spécifiques à une classe
void* T::operator new  ( std::size_t count );
(15)
void* T::operator new[]( std::size_t count );
(16)
void* T::operator new  ( std::size_t count, std::align_val_t al );
(17) (depuis C++17)
void* T::operator new[]( std::size_t count, std::align_val_t al );
(18) (depuis C++17)
Fonctions d'allocation de placement spécifiques à une classe
void* T::operator new  ( std::size_t count, /* args... */ );
(19)
void* T::operator new[]( std::size_t count, /* args... */ );
(20)
void* T::operator new  ( std::size_t count,
                         std::align_val_t al, /* args... */ );
(21) (depuis C++17)
void* T::operator new[]( std::size_t count,
                         std::align_val_t al, /* args... */ );
(22) (depuis C++17)

Tente d'allouer le nombre d'octets demandé, et la demande d'allocation peut échouer (même si le nombre d'octets demandé est zéro). Ces fonctions d'allocation sont appelées par les new expressions pour allouer la mémoire dans laquelle le nouvel objet sera ensuite initialisé. Elles peuvent également être appelées en utilisant la syntaxe d'appel de fonction normale.

1-8) Fonctions d'allocation remplaçables. La bibliothèque standard fournit des implémentations par défaut pour ces fonctions ; pour les effets des implémentations par défaut, voir ci-dessous.
9,10)Appelées par les expressions de placement newstandard. N'effectue aucune action et retourne ptr sans modification.
Si cette fonction est appelée via placement new et que ptr est un pointeur nul, le comportement est indéfini.
11-22)Fonctions d'allocation définies par l'utilisateur appelées par les new expressions.

Les surcharges (1-4) sont implicitement déclarées dans chaque unité de traduction même si l'en-tête <new> n'est pas inclus.

Voir new expression pour les critères de sélection de la surcharge.

Paramètres

count - nombre d'octets à allouer
ptr - pointeur vers une zone mémoire pour initialiser l'objet
tag - étiquette de désambiguïsation utilisée pour sélectionner les surcharges non levantes
al - alignement à utiliser, une valeur non valide conduit à un comportement indéfini

Valeur de retour

1-4) Si l'allocation réussit, un pointeur non nul p0 qui pointe vers une mémoire correctement alignée d'une taille d'au moins size et qui est différent de toute valeur précédemment retournée p1 , sauf si cette valeur p1 a été ultérieurement passée à une fonction de désallocation remplaçable ; si l'allocation échoue, ne retourne pas (une exception est levée, voir ci-dessous).
5-8) Identique à ( 1-4 ) , mais renvoie un pointeur nul si l'allocation échoue.
9,10) ptr
11-22) Identique à ( 1-4 ) si la fonction ne retourne pas en cas d'échec d'allocation, sinon identique à ( 5-8 ) .

Exceptions

1-4) Lance une exception d'un type qui correspondrait à un gestionnaire de type std::bad_alloc en cas d'échec d'allocation de mémoire.
11-22) Identique à ( 1-4 ) si la fonction ne retourne pas en cas d'échec d'allocation, sinon identique à ( 5-8 ) .

Remplacements globaux

Les surcharges (1-8) sont remplaçables. Les effets des versions par défaut sont :

1) Tente d'allouer le stockage demandé. Que la tentative implique un appel à std::malloc ou std::aligned_alloc est non spécifié.
  • Si la tentative réussit, retourne un pointeur vers le stockage alloué, le stockage est aligné sur l'alignement fondamental(jusqu'à C++17)le stockage est aligné sur __STDCPP_DEFAULT_NEW_ALIGNMENT__(depuis C++17).
  • Sinon, si actuellement aucun gestionnaire de nouveau n'est installé, lève std::bad_alloc.
  • Sinon, appelle le gestionnaire de nouveau actuellement installé.
    • Si le gestionnaire de nouveau retourne, commence une autre tentative d'allocation.
    • Sinon, quitte l'invocation en cours.
2) Retourne operator new(count).
3) Identique à (1), sauf que le stockage retourné est aligné sur al.
4) Retourne operator new(count, al).
5-8) Appelle (1-4) respectivement avec les mêmes arguments sauf pour tag.
  • Si l'appel retourne normalement, retourne le résultat de cet appel.
  • Sinon, retourne un pointeur nul.

Sur les implémentations autonomes, il est défini par l'implémentation si les versions par défaut de (1-8) satisfont les comportements requis ci-dessus. Il est recommandé que si l'une de ces versions par défaut satisfait les exigences d'une implémentation hébergée, elles le fassent toutes.

(depuis C++26)

Global operators new/delete remplacement :

#include <cstdio>
#include <cstdlib>
#include <new>

// no inline, required by [replacement.functions]/3
void* operator new(std::size_t sz)
{
    std::printf("1) new(size_t), size = %zu\n", sz);
    if (sz == 0)
        ++sz; // avoid std::malloc(0) which may return nullptr on success

    if (void *ptr = std::malloc(sz))
        return ptr;

    throw std::bad_alloc{}; // required by [new.delete.single]/3
}

// no inline, required by [replacement.functions]/3
void* operator new[](std::size_t sz)
{
    std::printf("2) new[](size_t), size = %zu\n", sz);
    if (sz == 0)
        ++sz; // avoid std::malloc(0) which may return nullptr on success

    if (void *ptr = std::malloc(sz))
        return ptr;

    throw std::bad_alloc{}; // required by [new.delete.single]/3
}

void operator delete(void* ptr) noexcept
{
    std::puts("3) delete(void*)");
    std::free(ptr);
}

void operator delete(void* ptr, std::size_t size) noexcept
{
    std::printf("4) delete(void*, size_t), size = %zu\n", size);
    std::free(ptr);
}

void operator delete[](void* ptr) noexcept
{
    std::puts("5) delete[](void* ptr)");
    std::free(ptr);
}

void operator delete[](void* ptr, std::size_t size) noexcept
{
    std::printf("6) delete[](void*, size_t), size = %zu\n", size);
    std::free(ptr);
}

int main()
{
    int* p1 = new int;
    delete p1;

    int* p2 = new int[10]; // guaranteed to call the replacement in C++11
    delete[] p2;
}

Résultat possible :

// Compiled with GCC-5 in C++17 mode to obtain the following:
1) op new(size_t), size = 4
4) op delete(void*, size_t), size = 4
2) op new[](size_t), size = 40
5) op delete[](void* ptr)

Les surcharges de operator new et operator new[] avec des paramètres supplémentaires définis par l'utilisateur ("formes de placement", versions (11-14)) peuvent être déclarées à la portée globale comme d'habitude, et sont appelées par les formes de placement correspondantes des expressions new.

Les formes de placement non allouantes de la bibliothèque standard de operator new (9,10) ne peuvent pas être remplacées et ne peuvent être personnalisées que si l'new expression de placement n'utilise pas la syntaxe ::new, en fournissant un placement spécifique à la classe new (19,20) avec une signature correspondante : void* T::operator new(std::size_t, void*) ou void* T::operator new[](std::size_t, void*).

La forme de placement void* operator new(std::size_t, std::size_t) n'est pas autorisée car la signature correspondante de la fonction de désallocation, void operator delete(void*, std::size_t), est une fonction de désallocation usuelle (non de placement).

(depuis C++14)

Surcharges spécifiques à une classe

Les fonctions d'allocation pour un seul objet et pour un tableau peuvent être définies comme fonctions membres publiques statiques d'une classe (versions (15-18)). Si elles sont définies, ces fonctions d'allocation sont appelées par les expressions new pour allouer de la mémoire pour des objets uniques et des tableaux de cette classe, sauf si l'expression new utilise la forme ::new qui contourne la recherche dans la portée de la classe. Le mot-clé static est facultatif pour ces fonctions : qu'il soit utilisé ou non, la fonction d'allocation est une fonction membre statique.

L'expression new recherche d'abord le nom de la fonction d'allocation appropriée dans la portée de la classe, puis dans la portée globale. Notez que, conformément aux règles de recherche de nom, toute fonction d'allocation déclarée dans la portée de la classe masque toutes les fonctions d'allocation globales pour les expressions new qui tentent d'allouer des objets de cette classe.

Lors de l'allocation d'objets et de tableaux d'objets dont l'alignement dépasse __STDCPP_DEFAULT_NEW_ALIGNMENT__, la résolution de surcharge est effectuée deux fois : d'abord pour les signatures de fonction conscientes de l'alignement, puis pour les signatures non conscientes de l'alignement. Cela signifie que si une classe avec un alignement étendu par new possède une fonction d'allocation spécifique à la classe non consciente de l'alignement, c'est cette fonction qui sera appelée, et non la fonction d'allocation globale consciente de l'alignement. Ceci est intentionnel : on attend du membre de la classe qu'il sache le mieux comment gérer cette classe.

(depuis C++17)

Lors de l'allocation d'objets et de tableaux d'objets dont l'alignement ne dépasse pas __STDCPP_DEFAULT_NEW_ALIGNMENT__, la résolution de surcharge est effectuée deux fois : d'abord pour les signatures de fonction non conscientes de l'alignement, puis pour les signatures conscientes de l'alignement.

(depuis C++20)
#include <cstddef>
#include <iostream>

// class-specific allocation functions
struct X
{
    static void* operator new(std::size_t count)
    {
        std::cout << "custom new for size " << count << '\n';
        return ::operator new(count);
    }
    
    static void* operator new[](std::size_t count)
    {
        std::cout << "custom new[] for size " << count << '\n';
        return ::operator new[](count);
    }
};

int main()
{
    X* p1 = new X;
    delete p1;
    X* p2 = new X[10];
    delete[] p2;
}

Sortie possible :

custom new for size 1
custom new[] for size 10

Les surcharges de operator new et operator new[] avec des paramètres supplémentaires définis par l'utilisateur (« formes de placement »), peuvent également être définies comme membres de classe (19-22)). Lorsque l'expression de placement new avec la signature correspondante recherche la fonction d'allocation correspondante à appeler, elle commence dans la portée de la classe avant d'examiner la portée globale, et si le placement spécifique à la classe new est fourni, il est appelé.

Lors de l'allocation d'objets et de tableaux d'objets dont l'alignement dépasse __STDCPP_DEFAULT_NEW_ALIGNMENT__, la résolution de surcharge pour les formes de placement est effectuée deux fois, comme pour les formes régulières : d'abord pour les signatures de fonction conscientes de l'alignement, puis pour les signatures non conscientes de l'alignement.

(depuis C++17)

Lors de l'allocation d'objets et de tableaux d'objets dont l'alignement ne dépasse pas __STDCPP_DEFAULT_NEW_ALIGNMENT__, la résolution de surcharge pour les formes de placement est effectuée deux fois, comme pour les formes régulières : d'abord pour les signatures de fonction non conscientes de l'alignement, puis pour les signatures conscientes de l'alignement.

(depuis C++20)
#include <cstddef>
#include <iostream>
#include <stdexcept>

struct X
{
    X() { throw std::runtime_error(""); }
    
    // custom placement new
    static void* operator new(std::size_t count, bool b)
    {
        std::cout << "custom placement new called, b = " << b << '\n';
        return ::operator new(count);
    }
    
    // custom placement delete
    static void operator delete(void* ptr, bool b)
    {
        std::cout << "custom placement delete called, b = " << b << '\n';
        ::operator delete(ptr);
    }
};

int main()
{
    try
    {
        [[maybe_unused]] X* p1 = new (true) X;
    }
    catch (const std::exception&)
    {}
}

Sortie :

custom placement new called, b = 1
custom placement delete called, b = 1

Si une fonction operator new au niveau de la classe est une fonction template, elle doit avoir le type de retour de void*, le premier argument std::size_t, et elle doit avoir deux paramètres ou plus. En d'autres termes, seules les formes de placement peuvent être des templates.

Notes

Bien que le placement non-allouant new ( 9,10 ) ne puisse pas être remplacé, une fonction avec la même signature peut être définie au niveau de la classe comme décrit ci-dessus. De plus, les surcharges globales qui ressemblent au placement new mais prennent un type de pointeur non-void comme second argument sont autorisées, donc le code qui veut garantir que le vrai placement new est appelé (par ex. std::allocator::construct ), doit utiliser :: new et aussi convertir le pointeur en void * .

Si le comportement d'une fonction de désallocation ne satisfait pas les contraintes par défaut, le comportement est indéfini.

Les fonctions suivantes doivent être thread-safe :

Les appels à ces fonctions qui allouent ou désallouent une unité de stockage particulière se produisent dans un ordre total unique, et chaque appel de désallocation se produit-avant la prochaine allocation (le cas échéant) dans cet ordre.

(depuis C++11)

Il n'est pas spécifié si les versions de bibliothèque de operator new effectuent des appels à std::malloc ou à std::aligned_alloc (depuis C++17) .

Pour charger un fichier volumineux, le mappage de fichiers via des fonctions spécifiques au système d'exploitation, par exemple, mmap sur POSIX ou CreateFileMapping ( A / W ) avec MapViewOfFile sur Windows, est préférable à l'allocation d'un tampon pour la lecture de fichiers.

Macro de test de fonctionnalité Valeur Std Fonctionnalité
__cpp_lib_freestanding_operator_new 202306L (C++26) Support autonome pour operator new remplaçable [1]
0 (C++26) Aucun support autonome
__cpp_lib_constexpr_new 202406L (C++26) constexpr placement new et new [ ]
  1. Formellement, cette macro se développe en 202306L si toutes les versions par défaut des fonctions d'allocation globales remplaçables satisfont aux exigences d'une implémentation hébergée.

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement tel que publié Comportement correct
CWG 521 C++98 toute classe dérivée de std::bad_alloc pouvait être levée,
même si la base std::bad_alloc est ambiguë ou inaccessible
l'exception levée doit correspondre
à un gestionnaire de type std::bad_alloc
LWG 9 C++98 des appels multiples pour allouer zéro
octet pouvaient produire le même pointeur
uniquement autorisé si tous ces pointeurs
précédemment produits ont été
passés à des fonctions de désallocation
LWG 206 C++98 le remplacement des fonctions d'allocation remplaçables
n'affectait pas les comportements par défaut des fonctions
d'allocation non levantes remplaçables correspondantes
les comportements par défaut
changent en conséquence
LWG 404 C++98 les remplacements des fonctions d'allocation
remplaçables pouvaient être déclarés inline
interdit, aucun diagnostic requis

Références

  • Norme C++23 (ISO/CEI 14882:2024) :
  • 17.7 Gestion dynamique de la mémoire [support.dynamic]
  • Norme C++20 (ISO/CEI 14882:2020) :
  • 17.6 Gestion dynamique de la mémoire [support.dynamic]
  • Norme C++17 (ISO/IEC 14882:2017) :
  • 21.6 Gestion dynamique de la mémoire [support.dynamic]
  • Norme C++14 (ISO/CEI 14882:2014) :
  • 18.6 Gestion dynamique de la mémoire [support.dynamic]
  • Norme C++11 (ISO/CEI 14882:2011) :
  • 18.6 Gestion dynamique de la mémoire [support.dynamic]
  • Norme C++03 (ISO/CEI 14882:2003) :
  • 18.4 Gestion dynamique de la mémoire [lib.support.dynamic]
  • Norme C++98 (ISO/CEI 14882:1998) :
  • 18.4 Gestion dynamique de la mémoire [lib.support.dynamic]

Voir aussi

[static] (C++23)
alloue de la mémoire en utilisant Allocator
(fonction membre statique publique de std::generator<Ref,V,Allocator>::promise_type )
fonctions de désallocation
(fonction)
obtient le gestionnaire new actuel
(fonction)
enregistre un nouveau gestionnaire
(fonction)
(obsolète en C++17) (supprimé en C++20)
obtient un stockage non initialisé
(fonction template)
alloue de la mémoire
(fonction)
alloue de la mémoire alignée
(fonction)