operator new, operator new[]
| 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.
newstandard. N'effectue aucune action et retourne ptr sans modification.new et que ptr est un pointeur nul, le comportement est indéfini.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
Exceptions
Remplacements globaux
Les surcharges (1-8) sont remplaçables. Les effets des versions par défaut sont :
- 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.
operator new(count).al.operator new(count, al).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 |
(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 |
(depuis C++17) |
|
Lors de l'allocation d'objets et de tableaux d'objets dont l'alignement ne dépasse pas |
(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 |
(depuis C++17) |
|
Lors de l'allocation d'objets et de tableaux d'objets dont l'alignement ne dépasse pas |
(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 [ ] |
- ↑ 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) |
|
|
(C++11)
|
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) |
|
|
(C++17)
|
alloue de la mémoire alignée
(fonction) |