web-dev-qa-db-fra.com

Pourquoi les fonctions de construction et de destruction de std :: allocator sont-elles déconseillées en c ++ 17?

La spécification c ++ 17 déprécie les membres construct et destroy des std::allocator objet. Le groupe de travail a fourni la justification de la dépréciation d'autres fonctions membres ici , sous le titre "Déprécier les membres redondants de std :: allocator".

Cependant, ils ne mentionnent pas spécifiquement pourquoi ces deux membres sont déconseillés ou quelle est la recommandation pour remplacer cette fonctionnalité. Je suppose que l'implication est d'utiliser std::allocator_traits::construct au lieu.

Je suis un peu confus quant à savoir si l'implémentation de construct peut en fait être encore nécessaire dans certains cas à cause de ce commentaire sur std::allocator_traits::construct

Étant donné que cette fonction fournit le retour automatique au placement new, la fonction membre construct () est une exigence d'allocateur facultative depuis C++ 11.

Pour les allocateurs personnalisés (par exemple pour la mémoire alignée sur une page utilisant memalign), le retour au placement new produira-t-il toujours le comportement correct?

46
Nicolas Holthaus

Le table des exigences d'allocateur indique que construct(c, args), s'il est fourni, doit "construire un objet de type C à c".

Il ne dit absolument rien 1) quels arguments doivent être passés au constructeur de C ou 2) comment ces arguments doivent être passés. C'est le choix de l'allocateur, et en fait, deux allocateurs de la norme jouent avec les arguments avant de les passer au constructeur de C: std::scoped_allocator_adaptor et std::pmr::polymorphic_allocator . Lors de la construction d'un std::pair, En particulier, les arguments qu'ils transmettent au constructeur de pair peuvent même ne pas ressembler à ceux qu'ils ont reçus.

Il n'y a pas non plus d'obligation de transmettre parfaitement; une construct(T*, const T&) de style C++ 03 est conforme si elle est inefficace.

std::allocatorconstruct et destroy sont déconseillés car ils sont inutiles: aucun bon code C++ 11 et ultérieur ne devrait les appeler directement, et ils n'ajoutent rien par rapport à la valeur par défaut .


La gestion de l'alignement de la mémoire devrait être la tâche de allocate, pas de construct.

25
T.C.

Les fonctions ont été supprimées avec d'autres du papier D0174R0 Déprécier les parties de la bibliothèque résiduelle en C++ 17 . Si nous regardons la section pertinente, nous avons

De nombreux membres de std :: allocator dupliquent de manière redondante un comportement qui est sinon produit par std::allocator_traits<allocator<T>>, et pourrait être supprimé en toute sécurité pour simplifier cette classe. De plus, addressof en tant que fonction libre remplace std::allocator<T>::address qui nécessite un objet allocateur du bon type. Enfin, les alias de type de référence ont été initialement fournis comme un moyen prévu d'extension avec d'autres allocateurs, mais se sont avérés ne pas servir un objectif utile lorsque nous avons spécifié les exigences d'allocateur (17.6.3.5 [allocator.requirements]).

Bien que nous ne puissions pas supprimer ces membres sans rompre la compatibilité descendante avec le code qui utilisait explicitement ce type d'allocateur, nous ne devrions pas recommander leur utilisation continue. Si un type souhaite prendre en charge les allocateurs génériques, il doit accéder aux fonctionnalités de l'allocateur via allocator_traits plutôt que d'accéder directement aux membres de l'allocateur - sinon il ne prendra pas correctement en charge les allocateurs qui s'appuient sur les traits pour synthétiser la valeur par défaut. comportements. De même, si un utilisateur n'a pas l'intention de prendre en charge les allocateurs génériques, il est beaucoup plus simple d'appeler directement new, delete et d'assumer directement les autres propriétés de std :: allocator telles que les types de pointeurs.

Emphase mine

Donc, le rationnel était que nous n'avons pas besoin de dupliquer tout le code dans l'allocateur puisque nous avons les traits d'allocateur. Si nous regardons std::allocator_traits nous verrons qu'il a

allocate
deallocate
construct
destroy
max_size

fonctions statiques afin que nous puissions les utiliser au lieu de celles de l'allocateur.

14
NathanOliver