C++ named requirements: Allocator
Encapsule les stratégies pour l'accès/adressage, l'allocation/désallocation et la construction/destruction d'objets.
Chaque composant de la bibliothèque standard susceptible d'allouer ou de libérer de la mémoire, depuis std::string , std::vector , et tous les conteneurs , à l'exception de std::array (depuis C++11) et de std::inplace_vector (depuis C++26) , jusqu'à std::shared_ptr et std::function (jusqu'à C++17) , le fait via un Allocator : un objet de type classe qui satisfait aux exigences suivantes.
L'implémentation de nombreuses exigences d'allocateur est optionnelle car tous les AllocatorAwareContainer accèdent aux allocateurs indirectement via std::allocator_traits , et std::allocator_traits fournit l'implémentation par défaut de ces exigences.
Table des matières |
Exigences
Étant donné
-
T, un type non const et non référence (jusqu'en C++11) type d'objet non const (depuis C++11) (jusqu'en C++17) type d'objet non qualifié cv (depuis C++17) , -
A, un type Allocator pour le typeT, -
a
, un objet de type
A, -
B, le type Allocator correspondant pour un type d'objet non qualifié cvU(obtenu par rebind deA), -
b
, un objet de type
B, - p , une valeur de type std:: allocator_traits < A > :: pointer , obtenue en appelant std:: allocator_traits < A > :: allocate ( ) ,
- cp , une valeur de type std:: allocator_traits < A > :: const_pointer , obtenue par conversion de p ,
- vp , une valeur de type std:: allocator_traits < A > :: void_pointer , obtenue par conversion de p ,
- cvp , une valeur de type std:: allocator_traits < A > :: const_void_pointer , obtenue par conversion de cp ou de vp ,
-
xp
, un pointeur déréférençable vers un type d'objet non qualifié cv
X, -
r
, une lvalue de type
Tobtenue par l'expression * p , - n , une valeur de type std:: allocator_traits < A > :: size_type .
| Identifiant de type | Type aliasé | Exigences |
|---|---|---|
A::pointer
(optionnel)
|
(non spécifié) [1] |
|
A::const_pointer
(optionnel)
|
(non spécifié) |
|
A::void_pointer
(optionnel)
|
(non spécifié) |
|
A::const_void_pointer
(optionnel)
|
(non spécifié) |
|
A::value_type
|
T
|
|
A::size_type
(optionnel)
|
(non spécifié) |
|
A::difference_type
(optionnel)
|
(non spécifié) |
|
A::template rebind<U>::other
(optionnel) [2] |
B
|
|
| Expression | Type de retour | Exigences |
|---|---|---|
| * p |
T&
|
|
| * cp | const T & | * cp et * p identifient le même objet. |
| p - > m | (tel quel) | Identique à ( * p ) . m , si ( * p ) . m est bien défini. |
| cp - > m | (tel quel) | Identique à ( * cp ) . m , si ( * cp ) . m est bien défini. |
| static_cast < A :: pointer > ( vp ) | (tel quel) | static_cast < A :: pointer > ( vp ) == p |
| static_cast < A :: const_pointer > ( cvp ) | (tel quel) | static_cast < A :: const_pointer > ( cvp ) == cp |
| std:: pointer_traits < A :: pointer > :: pointer_to ( r ) | (tel quel) |
| Expression | Type de retour | Exigences |
|---|---|---|
| a. allocate ( n ) |
A::pointer
|
Alloue un stockage adapté à un tableau de type
T[n]
et crée le tableau, mais ne construit pas les éléments du tableau. Peut lever des exceptions. Si
n
==
0
, la valeur de retour n'est pas spécifiée.
|
| a. allocate ( n, cvp ) (optionnel) | Identique à a. allocate ( n ) , mais peut utiliser cvp ( nullptr ou un pointeur obtenu à partir de a. allocate ( ) ) de manière non spécifiée pour améliorer la localité. | |
| a. allocate_at_least ( n ) (optionnel) (depuis C++23) |
std::
allocation_result
< A :: pointer > |
Alloue un stockage adapté à un tableau de type
T[cnt]
et crée le tableau, mais ne construit pas les éléments du tableau, puis retourne
{
p, cnt
}
, où
p
pointe vers le stockage et
cnt
n'est pas inférieur à
n
. Peut lever des exceptions.
|
| a. deallocate ( p, n ) | (non utilisé) |
Désalloue le stockage pointé par
p
, qui doit être une valeur retournée par un appel précédent à
allocate
ou
allocate_at_least
(depuis C++23)
qui n'a pas été invalidé par un appel intermédiaire à
deallocate
.
n
doit correspondre à la valeur précédemment passée à
allocate
ou être comprise entre la demande et le nombre d'éléments retournés via
allocate_at_least
(peut être égal à l'une ou l'autre borne)
(depuis C++23)
. Ne lève pas d'exceptions.
|
| a. max_size ( ) (optionnel) |
A::size_type
|
La plus grande valeur pouvant être passée à A :: allocate ( ) . |
| a. construct ( xp, args... ) (optionnel) | (non utilisé) |
Construit un objet de type
X
dans un stockage préalablement alloué à l'adresse pointée par
xp
, en utilisant
args...
comme arguments du constructeur.
|
| a. destroy ( xp ) (optionnel) | (non utilisé) |
Détruit un objet de type
X
pointé par
xp
, mais ne désalloue aucun stockage.
|
| Expression | Type de retour | Exigences |
|---|---|---|
| a1 == a2 | bool |
|
| a1 ! = a2 |
|
|
| Déclaration | Effet | Exigences |
| A a1 ( a ) |
Construit par copie
a1
de sorte que
a1
==
a
.
(Note : Chaque Allocator satisfait également CopyConstructible .) |
|
| A a1 = a | ||
| A a ( b ) |
Construit
a
de sorte que
B
(
a
)
==
b
et
A
(
b
)
==
a
.
(Note : Cela implique que tous les allocateurs liés par
rebind
maintiennent les ressources mutuelles, telles que les pools mémoire.)
|
|
| A a1 ( std :: move ( a ) ) | Construit a1 de sorte qu'il soit égal à la valeur précédente de a . |
|
| A a1 = std :: move ( a ) | ||
| A a ( std :: move ( b ) ) | Construit a de sorte qu'il soit égal à la valeur précédente de A ( b ) . |
|
| Type-id | Type alias | Exigences |
A::is_always_equal
(optionnel) |
std::true_type ou std::false_type ou dérivé de ceux-ci. |
|
| Expression | Type de retour | Description |
|---|---|---|
|
a.
select_on_container_copy_construction
(
)
(optionnel) |
A
|
|
| Type-id | Type alias | Description |
A::propagate_on_container_copy_assignment
(optionnel) |
std::true_type ou std::false_type ou dérivé de ceux-ci. |
|
A::propagate_on_container_move_assignment
(optionnel) |
|
|
A::propagate_on_container_swap
(optionnel) |
|
Notes :
- ↑ Voir également fancy pointers ci-dessous.
-
↑
rebindest uniquement optionnel (fourni par std::allocator_traits ) si cet allocateur est un modèle de la formeSomeAllocator<T, Args>, oùArgsreprésente zéro ou plusieurs paramètres de type template supplémentaires.
Étant donné
-
x1
et
x2
, objets de types (éventuellement différents)
X::void_pointer,X::const_void_pointer,X::pointer, ouX::const_pointer
-
Alors,
x1
et
x2
sont des valeurs de pointeur
équivalentes
si et seulement si
x1
et
x2
peuvent être explicitement converties en deux objets correspondants
px1
et
px2
de type
X::const_pointer, en utilisant une séquence de static_cast s utilisant uniquement ces quatre types, et l'expression px1 == px2 s'évalue à true .
Étant donné
-
w1
et
w2
, objets de type
X::void_pointer
-
Ensuite, pour l'expression
w1
==
w2
et
w1
!
=
w2
l'un ou les deux objets peuvent être remplacés par un
objet de valeur équivalente
de type
X::const_void_pointersans modification de la sémantique.
Étant donné
-
p1
et
p2
, objets de type
X::pointer
-
Ensuite, pour les expressions
p1
==
p2
,
p1
!
=
p2
,
p1
<
p2
,
p1
<=
p2
,
p1
>=
p2
,
p1
>
p2
,
p1
-
p2
, un ou les deux objets peuvent être remplacés par un objet
de valeur équivalente
de type
X::const_pointersans modification de la sémantique.
Les exigences ci-dessus permettent de comparer les
Container
iterator
s et
const_iterator
s.
Exigences de complétude de l'allocateur
Un type d'allocateur
|
(depuis C++17) |
Allocateurs avec état et sans état
Chaque Allocator est soit stateful soit stateless . Généralement, un allocateur stateful peut avoir des valeurs inégales qui désignent des ressources mémoire distinctes, tandis qu'un allocateur stateless désigne une seule ressource mémoire.
|
Bien que les allocateurs personnalisés ne soient pas tenus d'être sans état, l'utilisation d'allocateurs avec état dans la bibliothèque standard est définie par l'implémentation. L'utilisation de valeurs d'allocateur inégales peut entraîner des erreurs d'exécution définies par l'implémentation ou un comportement indéfini si l'implémentation ne prend pas en charge une telle utilisation. |
(until C++11) |
|
Les allocateurs personnalisés peuvent contenir un état. Chaque conteneur ou autre objet sensible aux allocateurs stocke une instance de l'allocateur fourni et contrôle le remplacement d'allocateur via std::allocator_traits . |
(since C++11) |
Les instances d'un type d'allocateur sans état se comparent toujours égales. Les types d'allocateurs sans état sont généralement implémentés comme des classes vides et conviennent pour l'optimisation de classe de base vide .
|
Le type membre
|
(depuis C++11) |
Pointeurs sophistiqués
Lorsque le type membre
pointer
n'est pas un type pointeur brut, il est communément appelé
« pointeur sophistiqué »
. Ces pointeurs ont été introduits pour supporter les architectures à mémoire segmentée et sont utilisés aujourd'hui pour accéder à des objets alloués dans des espaces d'adressage différents de l'espace d'adressage virtuel homogène accessible par les pointeurs bruts. Un exemple de pointeur sophistiqué est le pointeur indépendant du mapping d'adresses
boost::interprocess::offset_ptr
, qui permet d'allouer des structures de données nodales telles que
std::set
dans la mémoire partagée et les fichiers mappés en mémoire situés à des adresses différentes dans chaque processus. Les pointeurs sophistiqués peuvent être utilisés indépendamment de l'allocateur qui les a fournis
, via le modèle de classe
std::pointer_traits
(depuis C++11)
.
La fonction
std::to_address
peut être utilisée pour obtenir un pointeur brut à partir d'un pointeur sophistiqué.
(depuis C++20)
|
L'utilisation de pointeurs sophistiqués et de tailles personnalisées/de types différents dans la bibliothèque standard est conditionnellement prise en charge. Les implémentations peuvent exiger que les types membres
|
(jusqu'à C++11) |
ConceptPour la définition de l'objet de requête std::get_allocator , le concept suivant, uniquement à titre d'exposition, est défini.
Le concept uniquement à titre d'exposition /*simple-allocator*/ définit les contraintes minimales d'utilisabilité de l'exigence Allocator . |
(depuis C++26) |
Bibliothèque standard
Les composants suivants de la bibliothèque standard satisfont aux Allocator exigences :
|
l'allocateur par défaut
(modèle de classe) |
|
|
(C++11)
|
implémente un allocateur multi-niveaux pour les conteneurs multi-niveaux
(modèle de classe) |
|
(C++17)
|
un allocateur qui prend en charge le polymorphisme à l'exécution basé sur la
std::pmr::memory_resource
avec laquelle il est construit
(modèle de classe) |
Exemples
Démontre un allocateur C++11, à l'exception de
[[
nodiscard
]]
ajouté pour correspondre au style C++20.
#include <cstdlib> #include <iostream> #include <limits> #include <new> #include <vector> template<class T> struct Mallocator { typedef T value_type; Mallocator() = default; template<class U> constexpr Mallocator(const Mallocator <U>&) noexcept {} [[nodiscard]] T* allocate(std::size_t n) { if (n > std::numeric_limits<std::size_t>::max() / sizeof(T)) throw std::bad_array_new_length(); if (auto p = static_cast<T*>(std::malloc(n * sizeof(T)))) { report(p, n); return p; } throw std::bad_alloc(); } void deallocate(T* p, std::size_t n) noexcept { report(p, n, 0); std::free(p); } private: void report(T* p, std::size_t n, bool alloc = true) const { std::cout << (alloc ? "Alloc: " : "Dealloc: ") << sizeof(T) * n << " bytes at " << std::hex << std::showbase << reinterpret_cast<void*>(p) << std::dec << '\n'; } }; template<class T, class U> bool operator==(const Mallocator <T>&, const Mallocator <U>&) { return true; } template<class T, class U> bool operator!=(const Mallocator <T>&, const Mallocator <U>&) { return false; } int main() { std::vector<int, Mallocator<int>> v(8); v.push_back(42); }
Sortie possible :
Alloc: 32 bytes at 0x2020c20 Alloc: 64 bytes at 0x2023c60 Dealloc: 32 bytes at 0x2020c20 Dealloc: 64 bytes at 0x2023c60
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 publié | Comportement corrigé |
|---|---|---|---|
| LWG 179 | C++98 |
pointer
et
const_pointer
n'étaient pas
requis d'être comparables entre eux |
requis |
| LWG 199 | C++98 | la valeur de retour de a. allocate ( 0 ) était ambiguë | non spécifiée |
|
LWG 258
( N2436 ) |
C++98 |
la relation d'égalité entre allocateurs n'était
pas requise d'être réflexive, symétrique ou transitive |
requise d'être réflexive,
symétrique et transitive |
| LWG 274 | C++98 |
T
pouvait être un type qualifié const ou un type référence,
rendant std::allocator potentiellement mal formé [1] |
ces types interdits |
| LWG 2016 | C++11 |
les opérations de copie, déplacement et d'échange
d'allocateur pouvaient lever des exceptions lors de l'utilisation |
requises d'être non levantes |
| LWG 2081 |
C++98
C++11 |
les allocateurs n'étaient pas requis de supporter l'affectation
par copie (C++98) et l'affectation par déplacement (C++11) |
requis |
| LWG 2108 | C++11 | il n'y avait aucun moyen de montrer qu'un allocateur est sans état |
is_always_equal
fourni
|
| LWG 2263 | C++11 |
la résolution de
LWG issue 179
a été accidentellement supprimée en C++11
et non généralisée à
void_pointer
et
const_void_pointer
|
restaurée et généralisée |
| LWG 2447 | C++11 |
T
pouvait être un type objet qualifié volatile
|
ces types interdits |
| LWG 2593 | C++11 | le déplacement d'un allocateur pouvait modifier sa valeur | modification interdite |
| P0593R6 | C++98 |
allocate
n'était pas requis de créer un
objet tableau dans le stockage alloué |
requis |
-
↑
Les types membres
referenceetconst_referencede std::allocator sont définis respectivement commeT&etconst T&.-
Si
Test un type référence,referenceetconst_referencesont mal formés car une référence à une référence ne peut être formée (la compression de références a été introduite en C++11). -
Si
Test qualifié const,referenceetconst_referencesont identiques, et l'ensemble de surcharges de address() est mal formé.
-
Si