web-dev-qa-db-fra.com

Alternative au vecteur <bool>

Comme nous le savons tous (espérons-le), vector<bool> est totalement cassé et ne peut pas être traité comme un tableau c. Quel est le meilleur moyen d’obtenir cette fonctionnalité?

  • Utilisez un vector<char> à la place, ou
  • Utiliser une classe wrapper et avoir vector<bool_wrapper>

Comment gérez-vous ce problème? J'ai besoin de la fonctionnalité c_array ().

En tant que question secondaire, si je n’ai pas besoin de la méthode c_array (), quelle est la meilleure façon d’aborder ce problème si j’ai besoin d’un accès aléatoire? Devrais-je utiliser un deque ou autre chose?

Modifier:

  • J'ai besoin d'un dimensionnement dynamique.
  • Pour ceux qui ne savent pas, vector<bool> est spécialisé afin que chaque booléen prenne 1 bit Ainsi, vous ne pouvez pas le convertir en tableau de style c.
  • Je suppose que "wrapper" est un peu impropre. Je pensais à quelque chose comme ça:

Bien sûr, alors je dois lire dans un my_bool en raison de problèmes d'alignement possibles :(

struct my_bool
{
    bool the_bool;
};
vector<my_bool> haha_i_tricked_you;
81
rlbond

Utilisez std::deque si vous n'avez pas besoin du tableau, oui.

Sinon, utilisez une alternative vector ne se spécialisant pas sur bool, telle que celle dans Boost Container .

38
Daniel Earwicker

C'est un problème intéressant. 

Si vous avez besoin de ce qui aurait été un std :: vector s'il n'avait pas été spécialisé, alors peut-être que quelque chose comme ça fonctionnerait bien avec votre cas:

#include <vector>
#include <iostream> 
#include <algorithm>

class Bool
{
public:

    Bool(): m_value(){}
    Bool( bool value ) : m_value(value){}

    operator bool() const { return m_value;}

    // the following operators are to allow bool* b = &v[0]; (v is a vector here).
    bool* operator& () { return &m_value; }
const bool * const operator& () const { return &m_value; }

private:

    bool m_value;

};




int main()
{
    std::vector<Bool> working_solution(10, false);


    working_solution[5] = true;
    working_solution[7] = true;


    for( int i = 0; i < working_solution.size(); ++i )
    {
        std::cout<< "Id " << i << " = " << working_solution[i] << "(" <<(working_solution[i] ? "true" : "false") << ")" <<std::endl; // i used ? : to be sure the boolean evaluation is correct
    }

    std::sort( working_solution.begin(), working_solution.end());
    std::cout<< "--- SORTED! ---" << std::endl;

    for( int i = 0; i < working_solution.size(); ++i )
    {
            bool* b = &working_solution[i]; // this works!

        std::cout<< "Id " << i << " = " << working_solution[i] << "(" << (working_solution[i] ? "true" : "false") << ")" <<std::endl; // i used ? : to be sure the boolean evaluation is correct
    }

    std::cin.get();
    return 0;
}

J'ai essayé cela avec VC9 et cela semble bien fonctionner. L'idée de la classe Bool est de simuler le type bool en fournissant le même comportement et la même taille (mais pas le même type). Presque tout le travail est effectué par l'opérateur bool et les constructeurs de copie par défaut ici ..__ J'ai ajouté une sorte pour m'assurer qu'elle réagit comme prévu lors de l'utilisation d'algorithmes.

Pas sûr que cela convienne à tous les cas. Si cela répond à vos besoins, ce serait moins de travail que de réécrire une classe semblable à un vecteur ...

20
Klaim

Cela dépend de vos besoins. Je voudrais soit pour std::vector<unsigned char>. Écrire un wrapper peut être une bonne chose si vous utilisez seulement un sous-ensemble de fonctionnalités, sinon cela deviendra un cauchemar.

Comment gérez-vous ce problème? J'ai besoin de la fonctionnalité c_array ().

boost::container::vector<bool> :

La spécialisation vector <bool> a été assez problématique et plusieurs tentatives ont été infructueuses pour la déprécier ou la supprimer de la norme. Boost.Container ne l'implémente pas car il existe une solution supérieure Boost.DynamicBitset

...

Ainsi, boost :: container :: vector :: iterator renvoie de vraies références booléennes et fonctionne comme un conteneur totalement conforme. Si vous avez besoin d’une version optimisée pour la mémoire des fonctionnalités de boost :: container :: vector <bool>, veuillez utiliser Boost.DynamicBitset

11
Evgeny Panasyuk

Pensez à utiliser un vecteur <int>. Une fois que vous avez terminé la compilation et la vérification de type, bool et int ne sont que des mots-clés (modifier: apparemment ce n’est pas toujours vrai; ce sera le cas sur de nombreuses architectures de PC). Dans les cas où vous souhaitez convertir sans avertissement, utilisez "bool foo = !! bar", qui convertit zéro en faux et non nul en vrai.

Un vecteur <char> ou similaire utilise moins d’espace, bien qu’il puisse potentiellement subir une (très petite) frappe de vitesse dans certaines circonstances, car les caractères sont inférieurs à la taille de la machine. C’est, je crois, la principale raison pour laquelle les bools sont implémentés en utilisant ints au lieu de chars.

Si vous voulez vraiment une sémantique propre, j'aime aussi la suggestion de créer votre propre classe booléenne - qui ressemble à un bool, agit comme un bool, mais trompe la spécialisation des modèles.

De plus, bienvenue dans le club des personnes qui souhaitent que la spécialisation vectorielle <bool> soit supprimée de la norme C++ (avec bit_vector pour la remplacer). C'est là que se retrouvent tous les enfants cools :).

5
AHelps

La réponse la plus simple est d'utiliser vector<struct sb>sb est struct {boolean b};. Ensuite, vous pouvez dire Push_back({true}). Il semble bon.

4
Todd

Ce problème était déjà discuté sur comp.lang.c ++. Modéré. Solutions proposées: 

  • votre propre allocateur (basé sur std::allocator) et votre propre spécialisation de vecteurs;
  • utilisez std::deque (comme recommandé dans l'un des livres S. Mayers) - mais cela ne correspond pas à vos besoins;
  • faire POD bool wrapper; 
  • utilisez quelque chose (char/int/etc) de même taille que bool à la place bool

J'ai aussi vu de bonne heure une proposition pour un comité standard - introduire une macro (quelque chose comme STD_VECTOR_BOOL_SPECIAL) pour interdire cette spécialisation - mais, autant que je sache, cette proposition n'était pas implémentée dans les implémentations stl et n'était pas approuvée. 

Il semble que votre problème n'ait aucun moyen de le faire gentiment ... Peut-être en C++ 0x.

4
bayda

Ma solution de contournement préférée est une vector d'une énumération étendue qui a un type sous-jacent de bool. Cela se rapproche beaucoup du vector<bool> que nous aurions eu si le comité ne l'avait pas spécialisé.

enum class switch_status : bool { ON, OFF };

static_assert( sizeof( switch_status ) == 1 );

::std::vector<switch_status> switches( 20, switch_status::ON );

static_assert( ::std::is_same_v< decltype( switches.front() ), switch_status &> );
static_assert( ::std::is_same_v< decltype( switches.back()  ), switch_status &> );
static_assert( ::std::is_same_v< decltype( switches[ 0 ]    ), switch_status &> );

Vous aurez vos propres opinions sur la sagesse d’embrasser les castes de/à partir de bool:

enum class switch_status : bool { OFF = false, ON = true };

static_assert( static_cast< bool          >( switch_status::ON  ) == true               );
static_assert( static_cast< bool          >( switch_status::OFF ) == false              );
static_assert( static_cast< switch_status >( true               ) == switch_status::ON  );
static_assert( static_cast< switch_status >( false              ) == switch_status::OFF );
0
Tony E Lewis