105 votes

Est-ce que C++11 autorise vector<const T>?

Les exigences des conteneurs ont changé de C++03 à C++11. Alors que C++03 avait des exigences générales (par exemple, la constructibilité par copie et la capacité d'assignation pour vector), C++11 définit des exigences détaillées pour chaque opération sur le conteneur (section 23.2).

En conséquence, vous pouvez par exemple stocker un type qui est constructible par copie mais non assignable - tel qu'une structure avec un membre const - dans un vecteur tant que vous effectuez uniquement certaines opérations qui ne nécessitent pas d'assignation (la construction et push_back sont de telles opérations; insert ne l'est pas).

Ce qui me fait me demander : est-ce que cela signifie que la norme permet maintenant vector? Je ne vois aucune raison pour laquelle cela ne devrait pas être le cas - const T, tout comme une structure avec un membre const, est un type qui est constructible par copie mais non assignable - mais j'aurais peut-être manqué quelque chose.

(Une partie de ce qui me fait penser que j'ai peut-être manqué quelque chose, c'est que gcc trunk plante si vous essayez d'instancier vector, mais cela fonctionne avec vector où T a un membre const).

75voto

Bo Persson Points 42821

Non, je crois que les exigences de l'allocationneur disent que T peut être un "type d'objet non-const, non-référence".

Vous ne seriez pas capable de faire grand-chose avec un vecteur d'objets constants. Et un const vector serait presque pareil de toute façon.


De nombreuses années plus tard, cette réponse rapide et approximative semble toujours attirer des commentaires et des votes. Pas toujours positifs. :-)

Donc pour ajouter quelques références appropriées :

Pour le standard C++03, que j'ai sur papier, le Tableau 31 à la section [lib.allocator.requirements] dit :

T, U n'importe quel type

Non pas que n'importe quel type fonctionnait vraiment.

Ainsi, le standard suivant, C++11, dit dans un brouillon proche de [allocator.requirements] et maintenant Tableau 27 :

T, U, C n'importe quel type d'objet non-const, non-référence

ce qui est extrêmement proche de ce que j'ai initialement écrit ci-dessus de mémoire. C'est aussi de cela que parlait la question.

Cependant, dans C++14 (brouillon N4296) Tableau 27 dit maintenant :

T, U, C n'importe quel type d'objet non-const

Peut-être parce qu'une référence n'est peut-être pas un type d'objet après tout ?

Et maintenant dans C++17 (brouillon N4659) c'est le Tableau 30 qui dit :

T, U, C n'importe quel type d'objet non qualifié par des cv (6.9)

Ainsi non seulement le const est exclu, mais aussi le volatile. Probablement déjà connu, et juste une clarification.


Veuillez également consulter les informations de première main de Howard Hinnant, actuellement juste en dessous.

37voto

Howard Hinnant Points 59526

Mise à jour

Sous la réponse acceptée (et correcte), j'ai commenté en 2011:

En fin de compte : nous n'avons pas conçu les conteneurs pour contenir const T. Bien que j'y ai pensé. Et nous étions vraiment proches de le faire par accident. À ma connaissance, le point culminant actuel est le couple de fonctions membres surchargées address dans l'allocation par défaut : lorsque T est const, ces deux surcharges ont la même signature. Une façon facile de corriger cela serait de spécialiser std::allocator et de supprimer l'une des surcharges.

Avec le projet de norme C++17 à venir, il me semble que nous avons maintenant légalisé vector, et je crois aussi que nous l'avons fait accidentellement. :-)

P0174R0 supprime les surcharges de address de std::allocator. P0174R0 ne mentionne pas le support de std::allocator dans sa justification.

Correction

Dans les commentaires ci-dessous, T.C. souligne à juste titre que les surcharges de address sont obsolètes, non supprimées. Je m'excuse. Les membres obsolètes n'apparaissent pas dans la section 20.10.9 où est défini le std::allocator, mais sont plutôt relégués à la section D.9. J'ai omis de parcourir le chapitre D pour cette possibilité lorsque j'ai publié ceci.

Je vous remercie T.C. pour la correction. J'ai envisagé de supprimer cette réponse trompeuse, mais il est peut-être préférable de la laisser avec cette correction afin que peut-être cela empêchera quelqu'un d'autre de mal interpréter la spécification de la même manière que moi.

15voto

Lucio Paiva Points 368

Même si nous avons déjà de très bonnes réponses à ce sujet, j'ai décidé de contribuer avec une réponse plus pratique pour montrer ce qui peut être fait et ce qui ne peut pas l'être.

Donc, ceci ne fonctionne pas:

vector vec; 

Lisez les autres réponses pour comprendre pourquoi. Et, comme vous l'aurez deviné, ceci ne fonctionnera pas non plus:

vector> vec;

T n'est plus const, mais vector contient des shared_ptrs, pas des Ts.

En revanche, ceci fonctionne:

vector vec;
vector vec;  // la même chose que ci-dessus

Mais dans ce cas, const est l'objet pointé, pas le pointeur lui-même (qui est ce que le vector stocke). Cela serait équivalent à:

vector> vec;

C'est correct.

Mais si nous mettons const à la fin de l'expression, cela transforme maintenant le pointeur en un const, donc ce qui suit ne compilera pas:

vector vec;

Un peu déroutant, je l'admets, mais on s'y habitue.

7voto

Daniel Gouvêa Points 74

En complément des autres réponses, une autre approche consiste à utiliser :

vector> vec;

S'il s'agit du cas où vous voulez imposer que seul vec possède les éléments. Ou si vous voulez avoir une dynamique de déplacement des éléments dans vec et à un moment donné les déplacer à l'extérieur.

Comme cela a été souligné, la sémantique du pointeur const peut être déroutante, mais ce n'est pas le cas pour les shared_ptr et unique_ptr. const unique_ptr est un pointeur constant et unique_ptr est un objet pointé constant comme on pourrait s'y attendre.

-2voto

pigbrother Points 1

À ma connaissance, si vous voulez que chaque élément T de votre vecteur soit const, utilisez simplement const vector à la place. Car si votre vecteur est qualifié de constante, seules les méthodes qualifiées de constante qui ne modifieront aucun élément T peuvent être appelées.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X