Pourquoi le code suivant fonctionne-t-il?
struct A { std::vector subAs; };
A est un type incomplet, non? S’il y avait un vecteur de A *, je comprendrais. Mais ici je ne comprends pas comment ça marche. Cela semble être une définition récursive.
Ce document a été adopté en C ++ 17, qui permet d’utiliser des types incomplets dans certains conteneurs STL. Avant cela, c’était le comportement indéfini. Pour citer l’article:
Sur la base de la discussion à la réunion d’Issaquah, nous avons atteint le consensus pour procéder * avec l’approche – «Conteneurs de types incomplets», mais limiter la scope à
std::vector
,std::list
etstd::forward_list
, comme le premier pas.
Et pour ce qui est des modifications apscopes à la norme (c’est moi qui souligne):
Un type
T
incomplet peut être utilisé lors de l’instanciation duvector
si l’ allocateur satisfait aux exigences d’allocation-complétude (17.6.3.5.1). T doit être complet avant que tout membre de la spécialisation de vecteur résultant soit référencé.
Donc, vous l’avez, si vous laissez le std::allocator
par défaut en place lors de l’instanciation du std::vector
, alors il fonctionnera toujours avec un type T
incomplet selon l’article. sinon, votre Allocator sera instanciable avec un type T
incomplet.
A est un type incomplet, non? S’il y avait un vecteur de A *, je comprendrais. Mais ici je ne comprends pas comment ça marche. Cela semble être une définition récursive.
Il n’y a pas de récursivité. Sous une forme extrêmement simplifiée, c’est similaire à:
class A{ A* subAs; };
Techniquement, hormis la size
, la capacity
et éventuellement l’ allocator
, std::vector
n’a besoin que d’un pointeur vers un tableau dynamic de A
qu’il gère via son allocateur. (Et la taille d’un pointeur est connue au moment de la compilation.)
Ainsi, une implémentation peut ressembler à ceci:
namespace std{ template> class vector{ .... std::size_t m_capacity; std::size_t m_size; Allocator m_allocator; T* m_data; }; }