Как (надеюсь) мы все знаем, vector<bool>
он полностью сломан и не может рассматриваться как массив C. Как лучше всего получить эту функциональность? До сих пор я думал о следующих идеях:
- Используйте
vector<char>
вместо этого, или - Используйте класс-оболочку и
vector<bool_wrapper>
Как вы, ребята, справляетесь с этой проблемой? Мне нужен c_array()
функционал.
В качестве побочного вопроса, если мне не нужен c_array()
метод, как лучше всего решить эту проблему, если мне нужен произвольный доступ? Стоит мне использовать deque или что-то еще?
Редактировать:
- Мне нужен динамический размер.
- Для тех, кто не знает,
vector<bool>
это специализированный, так что каждыйbool
занимает 1 бит. Таким образом, вы не можете преобразовать его в массив в стиле C. - Я предполагаю, что термин «обертка» - это не совсем правильно. Я думал примерно так:
Конечно, тогда я должен прочитать my_bool
из-за возможных проблем с выравниванием :(
struct my_bool
{
bool the_bool;
};
vector<my_bool> haha_i_tricked_you;
vector<bool>
что в моем коде только что возникла ошибка гонки данных, так как я ожидал, что разные потоки смогут безопасно изменять разные элементы вектора одновременно. Решено с помощьюdeque<bool>
.Ответы:
Используйте,
std::deque
если вам не нужен массив, да.В противном случае используйте альтернативу
vector
, на которой не специализируетсяbool
, например, в Boost Container .источник
Это интересная проблема.
Если вам нужно то, что было бы std :: vector, если бы он не был специализированным, то, возможно, что-то подобное подойдет для вашего случая:
#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; }
Я пробовал это с VC9, и, похоже, все работает нормально. Идея класса Bool состоит в том, чтобы имитировать тип bool, обеспечивая такое же поведение и размер (но не тот же тип). Здесь почти вся работа выполняется оператором bool и конструкторами копирования по умолчанию. Я добавил сортировку, чтобы убедиться, что при использовании алгоритмов он реагирует так, как предполагается.
Не уверен, что он подойдет для всех случаев. Если это подходит для ваших нужд, это будет меньше работы, чем переписывание векторного класса ...
источник
sizeof(bool)
не обязательно1
»operator bool() const
Аняoperator bool&()
. Это позволяет лучше отражать поведение простого bool, поскольку он поддерживает присваивание и т. Д. В таких случаях, какv[0] = true;
я действительно не вижу проблемы с этим изменением, поэтому могу ли я внести изменения?Зависит от ваших потребностей. Я бы выбрал любой вариант
std::vector<unsigned char>
. Написание обертки может быть прекрасным, если вы используете только подмножество функциональности, иначе это станет кошмаром.источник
unsigned char
всегда является одним байтом, хотя реализацияuint8_t
может не поддерживаться.uint_fast8_t
может работать , хотя , если намерение состоит в том, чтобы сделать его ясно , что это один байт , а не символ, но вы можете также использоватьstd::byte
затемboost::container::vector<bool>
:источник
Рассмотрите возможность использования вектора <int>. Как только вы пройдете компиляцию и проверку типов, bool и int будут просто машинными словами (правка: очевидно, это не всегда верно; но будет верным для многих архитектур ПК). В тех случаях, когда вы хотите преобразовать без предупреждения, используйте «bool foo = !! bar», который преобразует ноль в ложь и ненулевое значение в истину.
Vector <char> или аналогичный будет использовать меньше места, хотя он также может получить (очень маленький) удар по скорости в некоторых обстоятельствах, потому что символы меньше размера машинного слова. Я считаю, что это основная причина того, что bools реализованы с использованием целых чисел вместо символов.
Если вам действительно нужна чистая семантика, мне также нравится предложение создать свой собственный логический класс - выглядит как bool, действует как bool, но обманывает специализацию шаблона.
Также добро пожаловать в клуб людей, которые хотят исключить специализацию vector <bool> из стандарта C ++ (заменив ее bit_vector). Здесь тусуются все крутые ребята :).
источник
Эта проблема уже обсуждалась на comp.lang.c ++. Moderated. Предлагаемые решения:
std::allocator
) и собственная векторная специализация;std::deque
(как раньше рекомендовалось в одной из книг С. Майерса) - но это не для ваших требований;bool
обертку POD ;char
/int
/ etc) того же размера, что иbool
вместо этогоbool
;Также рано я увидел предложение для стандартного комитета - ввести макрос (что-то вроде
STD_VECTOR_BOOL_SPECIAL
), чтобы запретить эту специализацию - но AFAIK это предложение не было реализовано в реализациях stl и не было одобрено.Кажется, у вашей проблемы нет способов сделать это красиво ... Может быть, в C ++ 0x.
источник
Самый простой ответ - использовать
vector<struct sb>
гдеsb
естьstruct {boolean b};
. Тогда можно сказатьpush_back({true})
. Выглядит неплохо.источник
Я предпочитаю обходной путь -
vector
перечисление с ограниченной областью действия, в основе которого лежит типbool
. Это очень близко к тому,vector<bool>
что было бы, если бы комитет не специализировался на этом.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 &> );
У вас будет свое собственное мнение о целесообразности использования приведений в / из
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 );
источник