91 votes

Pourquoi est-libc++de vecteur<bool>::const_reference pas bool?

Section 23.3.7 Classe vector<bool> [vecteur.bool], paragraphe 1, les états:

template <class Allocator> class vector<bool, Allocator> {
public:
    // types:
    typedef bool              const_reference;
    ...

Toutefois, ce programme ne parvient pas à compiler lors de l'utilisation de la libc++:

#include <vector>
#include <type_traits>

int
main()
{
    static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}

En outre, je note que la norme C++ a été conforme à cette spécification tous le chemin du retour vers C++98. Et de plus, je remarque que la libc++ a toujours pas suivi cette spécification depuis l'introduction de la libc++.

Quelle est la motivation de cette non-conformité?

98voto

Howard Hinnant Points 59526

La motivation pour cette extension, qui est détectable par un programme conforme, et donc non conforme, est de faire de la vector<bool> se comportent plus comme des vector<char> à l'égard de références (const et autre).

Introduction

Depuis 1998, vector<bool> a été considéré comme "pas tout à fait un conteneur." LWG 96, l'un des tout premiers LWG questions, a lancé le débat. Aujourd'hui, 17 ans plus tard, vector<bool> reste en grande partie inchangée.

Le présent document passe en certains exemples spécifiques sur la façon dont le comportement de l' vector<bool> diffère de tous les autres instanciation d' vector, portant ainsi préjudice code générique. Toutefois, le même article discute longuement de la très belle performance de propriétés vector<bool> peut avoir, si elle est correctement mise en œuvre.

Résumé: vector<bool> n'est pas un mauvais conteneur. Il est tout à fait utile. Il a juste un mauvais nom.

Retour à l' const_reference

Comme présenté ci-dessus, et qui sont détaillés ici, ce qui est mauvais sur vector<bool> , c'est qu'il se comporte différemment dans le code générique que les autres vector instanciations. Voici un exemple concret:

#include <cassert>
#include <vector>

template <class T>
void
test(std::vector<T>& v)
{
    using const_ref = typename std::vector<T>::const_reference;
    const std::vector<T>& cv = v;
    const_ref cr = cv[0];
    assert(cr == cv[0]);
    v[0] = 1;
    assert(true == cv[0]);
    assert(cr == cv[0]);  // Fires!
}

int
main()
{
    std::vector<char> vc(1);
    test(vc);
    std::vector<bool> vb(1);
    test(vb);
}

La spécification de la norme dit que l'assertion marquée // Fires! va déclencher, mais seulement lorsque l' test est exécuté avec un vector<bool>. Lors de l'exécution avec un vector<char> (ou tout vector en plus d' bool lorsqu'une non-valeur par défaut T est affectée), le test passe.

La libc++ mise en œuvre cherché à minimiser les effets négatifs de l'avoir vector<bool> se comportent différemment dans le code générique. Une chose qu'il a fait pour y parvenir est de faire vector<T>::const_reference un proxy de référence, tout comme le spécifiée vector<T>::reference, sauf que vous ne pouvez pas assigner à travers elle. C'est, sur la libc++, vector<T>::const_reference est essentiellement un pointeur vers la peu l'intérieur de l' vector, au lieu d'une copie de ce bit.

Sur la libc++ ci-dessus test passe pour les deux vector<char> et vector<bool>.

À quel coût?

L'inconvénient est que cette extension est détectable, comme indiqué dans la question. Cependant, très peu de programmes de soins sur le type exact de cet alias, et plus de programmes de soins sur le comportement.

Quelle est la motivation de cette non-conformité?

Pour donner de la libc++ client un meilleur comportement dans le code générique, et peut-être après un essai sur le terrain, proposer cette extension à une future norme C++ pour l'amélioration de l'ensemble de C++ de l'industrie.

Une telle proposition pourrait prendre la forme d'un nouveau conteneur (par exemple, bit_vector) qui a le même API, comme aujourd'hui, vector<bool>, mais avec quelques améliorations telles que l' const_reference discutés ici. Suivie par la dépréciation (et de l'éventuelle suppression) de l' vector<bool> de la spécialisation. bitset pourrait également utiliser un peu de mise à niveau dans ce département, par exemple, ajouter const_reference, et un ensemble d'itérateurs.

C'est, avec le recul bitset est vector<bool> (ce qui devrait être renommé bit_vector -- ou quoi que ce soit), que array est vector. Et l'analogie doit être vrai si oui ou non nous parlons bool le value_type de vector et array.

Il existe plusieurs exemples de C++11 et C++14 caractéristiques qui ont commencé comme des extensions dans la libc++. C'est la façon dont les normes évoluent. Réelle démontré positive de l'expérience de terrain, exerce une forte influence. Les normes folk est un conservateur tas quand il s'agit de changer les spécifications existantes (comme ils devraient l'être). Deviner, même lorsque vous êtes sûr de deviner correctement, est une stratégie risquée pour l'évolution d'une norme internationalement reconnue.

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