it-swarm.com.de

Alternative zum Vektor <bool>

Wie (hoffentlich) wir alle wissen, ist vector<bool> total kaputt und kann nicht als c-Array behandelt werden. Was ist der beste Weg, um diese Funktionalität zu erhalten? Die Ideen, an die ich bisher gedacht habe, sind:

  • Verwenden Sie stattdessen einen vector<char> oder
  • Verwenden Sie eine Wrapper-Klasse und haben Sie vector<bool_wrapper>

Wie geht ihr mit diesem Problem um? Ich brauche die c_array () - Funktionalität.

Als Nebenfrage: Wenn ich die c_array () -Methode nicht benötige, wie gehe ich am besten an dieses Problem heran, wenn ich Direktzugriff benötige? Soll ich eine Deque oder etwas anderes verwenden?

Bearbeiten:

  • Ich brauche dynamische Größenanpassung.
  • Für diejenigen, die es nicht wissen, ist vector<bool> so spezialisiert, dass jeder Bool 1 Bit benötigt. Daher können Sie es nicht in ein Array im C-Stil konvertieren.
  • Ich denke, "Wrapper" ist ein bisschen irreführend. Ich dachte so etwas:

Natürlich muss ich dann wegen möglicher Ausrichtungsprobleme in my_bool einlesen :(

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

Verwenden Sie std::deque , wenn Sie das Array nicht benötigen, ja.

Verwenden Sie andernfalls eine alternative vector, die sich nicht auf bool spezialisiert, z. B. die in Boost Container .

38

Das ist ein interessantes Problem. 

Wenn Sie benötigen, was ein std :: vector gewesen wäre, wenn es nicht spezialisiert wäre, dann würde vielleicht etwas in Ihrem Fall funktionieren:

#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;
}

Ich habe dies mit VC9 ausprobiert und es scheint gut zu funktionieren. Die Idee der Bool-Klasse besteht darin, den Bool-Typ zu simulieren, indem dasselbe Verhalten und dieselbe Größe (jedoch nicht derselbe Typ) bereitgestellt wird. Fast die gesamte Arbeit wird vom Bool-Operator und den Standard-Copy-Konstruktoren ausgeführt .. Ich fügte eine Sortierung hinzu, um sicherzustellen, dass er bei der Verwendung von Algorithmen wie angenommen reagiert.

Ich bin nicht sicher, ob es für alle Fälle geeignet wäre. Wenn es für Ihre Bedürfnisse geeignet ist, wäre es weniger Arbeit, als eine vektorähnliche Klasse umzuschreiben ...

20
Klaim

Kommt auf deine Bedürfnisse an. Ich würde entweder std::vector<unsigned char> wählen. Das Schreiben eines Wrappers kann in Ordnung sein, wenn Sie nur einen Teil der Funktionalität verwenden, andernfalls wird dies zu einem Albtraum.

Wie geht ihr mit diesem Problem um? Ich brauche die c_array () - Funktionalität.

boost::container::vector<bool> :

Die vector <bool> -Spezialisierung war ziemlich problematisch, und es gab mehrere erfolglose Versuche, sie abzulehnen oder vom Standard zu entfernen. Boost.Container implementiert es nicht, da es eine überlegene Boost.DynamicBitset -Lösung gibt. 

...

Boost :: container :: vector :: iterator gibt echte Bool-Referenzen zurück und funktioniert als vollständig kompatibler Container. Wenn Sie eine speicheroptimierte Version von boost :: container :: vector <bool> benötigen, verwenden Sie bitte Boost.DynamicBitset

11
Evgeny Panasyuk

Erwägen Sie die Verwendung eines Vektors <int>. Wenn Sie die Kompilierung und Typüberprüfung hinter sich gelassen haben, sind bool und int nur noch Maschinenwörter (edit: Anscheinend ist dies nicht immer wahr; wird aber auf vielen PC-Architekturen zutreffen). In den Fällen, in denen Sie ohne Warnung konvertieren möchten, verwenden Sie "bool foo = !! bar", wodurch Null in False und Nicht-Null in True konvertiert wird.

Ein Vektor <char> oder ähnliches beansprucht weniger Speicherplatz, kann jedoch unter Umständen einen (sehr kleinen) Geschwindigkeitstreffer aushalten, da Zeichen weniger als die Word-Größe des Computers sind. Dies ist meiner Meinung nach der Hauptgrund dafür, dass Bools mit Ints statt mit Zeichen implementiert werden.

Wenn Sie wirklich saubere Semantik wollen, gefällt mir auch der Vorschlag, eine eigene boolesche Klasse zu erstellen - sie sieht aus wie ein Bool, wirkt wie ein Bool, täuscht aber die Vorlagenspezialisierung.

Willkommen im Club von Leuten, die die Vektor-Spezialisierung <bool> vom C++ - Standard (mit bit_vector als Ersatz) entfernen möchten. Hier hängen alle coolen Kinder rum :).

5
AHelps

Die einfachste Antwort lautet vector<struct sb>, wobei sbstruct {boolean b}; ist. Dann können Sie Push_back({true}) sagen. Es scheint gut.

4
Todd

Dieses Problem wurde in comp.lang.c ++ bereits Considered moderiert. Lösungsvorschläge: 

  • eigener Allokator (basierend auf std::allocator) und eigene Vektorspezialisierung;
  • verwenden Sie std::deque (so früh wurde in einem der Bücher S. Mayers empfohlen) - aber dies nicht für Ihre Anforderungen;
  • pOD bool wrapper machen; 
  • verwenden Sie etwas (char/int/etc) mit derselben Größe wie bool statt bool

Auch früh sah ich einen Vorschlag für ein Standardkomitee - Makro einführen (etwas wie STD_VECTOR_BOOL_SPECIAL), um diese Spezialisierung zu verbieten - aber AFAIK wurde dieser Vorschlag nicht in stl-Implementierungen implementiert und nicht genehmigt. 

Es scheint, dass Ihr Problem keine Möglichkeiten hat, dies schön zu tun ... Vielleicht in C++ 0x.

4
bayda

Meine bevorzugte Problemumgehung ist eine Variable vom Typ vector, für die der Typ bool zugrunde liegt. Dies kommt dem vector<bool> ziemlich nahe, den wir gehabt hätten, wenn das Komitee es nicht spezialisiert hätte.

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 &> );

Sie haben Ihre eigene Meinung über die Weisheit, Casts zu/von bool zu umarmen:

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