Jak (miejmy nadzieję) wszyscy wiemy, vector<bool>
jest całkowicie zepsuty i nie może być traktowany jako tablica C. Jaki jest najlepszy sposób na uzyskanie tej funkcjonalności? Do tej pory pomysły, o których myślałem, to:
- Użyj
vector<char>
zamiast tego lub - Użyj klasy opakowania i użyj
vector<bool_wrapper>
Jak radzicie sobie z tym problemem? Potrzebuję c_array()
funkcjonalności.
Na marginesie, jeśli nie potrzebuję c_array()
metody, jaki jest najlepszy sposób rozwiązania tego problemu, jeśli potrzebuję dostępu losowego? Powinienem użyć deque czy czegoś innego?
Edytować:
- Potrzebuję dynamicznej zmiany rozmiaru.
- Dla tych, którzy nie wiedzą,
vector<bool>
jest wyspecjalizowany, więc każdybool
zajmuje 1 bit. Dlatego nie możesz przekonwertować go na tablicę w stylu C. - Myślę, że „opakowanie” jest trochę mylące. Myślałem coś takiego:
Oczywiście muszę wtedy przeczytać my_bool
ze względu na możliwe problemy z wyrównaniem :(
struct my_bool
{
bool the_bool;
};
vector<my_bool> haha_i_tricked_you;
vector<bool>
właśnie spowodowałem błąd wyścigu danych w moim kodzie, ponieważ spodziewałem się, że różne wątki będą w stanie jednocześnie bezpiecznie modyfikować różne elementy w wektorze. Rozwiązany za pomocądeque<bool>
.Odpowiedzi:
Użyj,
std::deque
jeśli nie potrzebujesz tablicy, tak.W przeciwnym razie użyj alternatywy
vector
, która nie jest specjalizująca się w tej dziedziniebool
, takiej jak ta w Kontenerze Wzmocnienia .źródło
To ciekawy problem.
Jeśli potrzebujesz czegoś, co byłoby std :: vector, gdyby nie było wyspecjalizowane, może coś takiego działałoby dobrze w twoim przypadku:
#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* 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; }
Próbowałem tego z VC9 i wydaje się, że działa dobrze. Ideą klasy Bool jest symulowanie typu bool przez zapewnienie tego samego zachowania i rozmiaru (ale nie tego samego typu). Prawie cała praca jest wykonywana przez operatora bool i domyślne konstruktory kopiujące tutaj. Dodałem sortowanie, aby upewnić się, że zareaguje zgodnie z założeniami podczas korzystania z algorytmów.
Nie jestem pewien, czy będzie pasował do wszystkich przypadków. Jeśli jest odpowiedni dla twoich potrzeb, byłoby mniej pracy niż przepisanie klasy wektorowej ...
źródło
sizeof(bool)
nie musi być1
”operator bool() const
naoperator bool&()
. To sprawia, że lepiej odzwierciedla zachowanie prostej wartości logicznej, ponieważ obsługuje przypisanie itp. W przypadkach, gdyv[0] = true;
naprawdę nie widzę problemu z tą zmianą, więc czy mogę dokonać edycji?Zależy od Twoich potrzeb. Zrobiłbym to
std::vector<unsigned char>
. Napisanie opakowania może być w porządku, jeśli używasz tylko części funkcji, w przeciwnym razie stanie się koszmarem.źródło
unsigned char
jest zawsze jednobajtowa, podczas gdyuint8_t
implementacja może nie być obsługiwana.uint_fast8_t
może zadziałać, jeśli intencją jest wyjaśnienie, że jest to pojedynczy bajt, a nie znak, ale równie dobrze możesz użyćstd::byte
wtedyboost::container::vector<bool>
:źródło
Rozważ użycie wektora <int>. Gdy przejdziesz przez kompilację i sprawdzanie typów, bool i int są tylko słowami maszynowymi (edycja: najwyraźniej nie zawsze jest to prawda; ale będzie prawdą na wielu architekturach komputerów PC). W przypadkach, w których chcesz dokonać konwersji bez ostrzeżenia, użyj „bool foo = !! bar”, które konwertuje zero na fałsz i niezerowe na prawdę.
Wektor <char> lub podobny będzie zużywał mniej miejsca, chociaż może również w pewnych okolicznościach spowodować (bardzo małą) szybkość, ponieważ znaki są mniejsze niż rozmiar słowa maszynowego. To jest, jak sądzę, główny powód, dla którego boole są implementowane przy użyciu ints zamiast chars.
Jeśli naprawdę chcesz czystej semantyki, podoba mi się również sugestia stworzenia własnej klasy boolowskiej - wygląda jak bool, działa jak bool, ale oszukuje specjalizację szablonu.
Witamy w gronie ludzi, którzy chcą, aby specjalizacja vector <bool> została usunięta ze standardu C ++ (z bit_vector, aby ją zastąpić). Tutaj spędzają czas wszystkie fajne dzieciaki :).
źródło
Ten problem był już omawiany na comp.lang.c ++. Moderated. Proponowane rozwiązania:
std::allocator
) i własną specjalizację wektorów;std::deque
(jak wcześnie było zalecane w jednej z książek S. Mayersa) - ale to nie do twoich wymagań;bool
opakowanie POD ;char
/int
/ etc) o takim samym rozmiarze jakbool
zamiast tegobool
;Wcześnie też spotkałem się z propozycją komitetu standaryzacyjnego - wprowadzić makro (coś w rodzaju
STD_VECTOR_BOOL_SPECIAL
), żeby nie zezwalać na tę specjalizację - ale AFAIK ta propozycja nie została zaimplementowana w implementacjach STL i nie została zatwierdzona.Wygląda na to, że twój problem nie ma sposobu, aby to ładnie zrobić ... Może w C ++ 0x.
źródło
Najprostsza odpowiedź brzmi:
vector<struct sb>
gdziesb
jeststruct {boolean b};
. Wtedy możesz powiedziećpush_back({true})
. Wygląda dobrze.źródło
Moim preferowanym obejściem jest
vector
wyliczenie o określonym zakresie, które ma podstawowy typbool
. Jest to bardzo zbliżone do tego,vector<bool>
które mielibyśmy, gdyby komitet nie wyspecjalizował tego.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 &> );
Będziesz mieć własne opinie na temat mądrości przyjmowania rzutów do / z
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 );
źródło