std :: vector fonctionne avec des classes qui ne sont pas constructibles par défaut?

J’ai lu à plusieurs endroits que std :: vector exige que son argument de modèle soit constructible par défaut. Aujourd’hui, je viens de l’essayer avec l’une de mes classes qui a un constructeur delete d default, et à ma grande surprise, cela semble fonctionner correctement (avec le constructeur par défaut de std :: vector). Ce comportement est-il portable ou s’agit-il d’un détail d’implémentation de la STL de gcc et devrais-je supposer que vector exige que son argument de modèle soit constructible par défaut?

C ++ 03 CopyConstructible que les types stockés dans un conteneur soient CopyConstructible et Assignable (voir §23.1 Configuration requirejse pour le conteneur). Cependant, dans C ++ 11, ces exigences sont assouplies et ont tendance à s’appliquer aux opérations effectuées sur le conteneur. Donc, une construction simple par défaut n’a pas d’exigences (voir l’annexe 96, §23.1 du standard C ++ 11).

Dès que vous essayez de copier un vecteur ou d’y insérer des éléments, vous devez répondre aux exigences CopyInsertable , CopyAssignable , EmplaceConstructible , MoveInsertable , MoveAssignable etc.

Deux membres vector nécessitent un T constructible par défaut en C ++ 11:

 explicit vector(size_type n); void resize(size_type sz); 

Rien d’autre ne fait. Donc, si vous utilisez ces signatures, vous devez avoir un type constructible par défaut, sinon vous ne l’êtes pas.

std::vector ne nécessite pas inconditionnellement que son type d’éléments soit constructible par défaut.

La spécification d’origine de std::vector (C ++ 98, C ++ 03) ne tente même jamais de construire ses éléments par défaut en interne. Tous les nouveaux éléments sont toujours construits à partir d’un object fourni sous forme d’argument “de l’extérieur” (par le code appelant). Cela signifie que chaque fois que vous avez besoin d’éléments construits par défaut dans votre vecteur, c’est votre côté du code (l’appelant) qui doit le construire par défaut et le fournir à std::vector tant qu’élément “original” à copier. .

Par exemple, lorsque vous faites quelque chose comme ça en C ++ 98

 std::vector v(42); v.resize(64); 

il se développe réellement dans

 std::vector v(42, some_type(), allocator_type()); v.resize(64, some_type()); 

via le mécanisme d’argument par défaut. En d’autres termes, l’élément “original” construit par défaut est fourni au constructeur du vecteur par le code appelant, non créé en interne par le vecteur.

C ++ 11 a changé cela et maintenant std::vector a des méthodes qui effectuent la construction par défaut de ses éléments en interne . Cela n’exige toujours pas que les éléments vectoriels soient constructibles par défaut. Cela signifie simplement que vous avez besoin d’éléments constructibles par défaut pour utiliser ces méthodes spécifiques de std::vector .

Les modèles sont en quelque sorte faiblement typés. Autrement dit, le constructeur par défaut manquant ne sera pas détecté tant que votre code n’appellera pas la méthode dans laquelle il est utilisé, peut-être en interne, ce qui produira une erreur lors de la compilation.

Cependant, à moins de ne pas toucher aux méthodes qui utilisent le constructeur par défaut en interne, vous êtes “en sécurité”. Cependant, je ne sais pas quel est le sous-ensemble “sûr”, et je soupçonne que ce n’est pas défini par la norme. Exemple: la copie vectorielle peut utiliser le resize , qui à son tour peut utiliser le constructeur par défaut.