Альтернатива вектору <bool>

Как мы надеемся, мы все знаем, что 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;

Ответ 1

Используйте std::deque, если вам не нужен массив, да.

В противном случае используйте альтернативу vector, которая не специализируется на bool, например, в Boost Container.

Ответ 2

Это интересная проблема.

Если вам понадобится 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 * 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;
}

Я пробовал это с VC9, и, похоже, он работает нормально. Идея класса Bool заключается в том, чтобы моделировать тип bool, обеспечивая одинаковое поведение и размер (но не тот же тип). Практически вся работа выполняется оператором bool и конструкторами копирования по умолчанию здесь. Я добавил сортировку, чтобы убедиться, что она реагирует так, как предполагается при использовании алгоритмов.

Не уверен, что это подойдет для всех случаев. Если это правильно для ваших нужд, это будет меньше работы, чем переписывание векторного класса...

Ответ 3

В зависимости от ваших потребностей. Я бы пошел на std::vector<unsigned char>. Написание обертки может быть прекрасным, если вы используете только подмножество функций, иначе это станет кошмаром.

Ответ 4

Как вы, ребята, справляетесь с этой проблемой? Мне нужна функция c_array().

boost::container::vector<bool>:

вектор < bool > специализация была довольно проблематичной, и было несколько неудачных попыток осудить или удалить ее из стандарта. Boost.Container не реализует его, поскольку существует превосходное решение Boost.DynamicBitset.

...

So boost:: container:: vector:: iterator возвращает реальные ссылки bool и работает как полностью совместимый контейнер. Если вам нужна оптимизированная память версии boost:: container:: vector < bool > , используйте Boost.DynamicBitset.

Ответ 5

Рассмотрим использование вектора <int> . После того, как вы закончите компиляцию и проверку типов, bool и int - это просто машинные слова (редактирование: по-видимому, это не всегда так, но будет верно на многих архитектурах ПК). В тех случаях, когда вы хотите конвертировать без предупреждения, используйте "bool foo =!! bar", который преобразует ноль в false и не равен нулю в true.

Вектор <char> или аналогичный будет использовать меньше места, хотя в некоторых случаях он может иметь (очень малую) скорость, потому что символы меньше размера машинного слова. Это, я считаю, главная причина, по которой bools реализованы с использованием ints вместо символов.

Если вам действительно нужна чистая семантика, мне также нравится предложение создать собственный булевский класс - выглядит как bool, действует как bool, но обманывает специализацию шаблона.

Кроме того, добро пожаловать в клуб людей, которые хотят вектор <bool> специализация упала со стандарта С++ (с помощью bit_vector для ее замены). Это где все крутые дети болтаются:).

Ответ 6

Эта проблема уже была обсуждалась на comp.lang.С++. moderated. Предлагаемые решения:

  • ваш собственный распределитель (на основе std::allocator) и собственной векторной специализации;
  • использовать std::deque (как было раннее рекомендовано в одной из книг С. Майерса) - но это не для ваших требований;
  • сделать упаковку POD bool;
  • используйте что-то (char/int/etc) с тем же размером, что и bool вместо bool;

Также рано я увидел предложение для стандартного комитета - ввести макрос (что-то вроде STD_VECTOR_BOOL_SPECIAL), чтобы запретить эту специализацию, - но AFAIK это предложение не было реализовано в реализациях stl и не было одобрено.

Кажется, что у вашей проблемы нет способов сделать это красиво... Возможно, в С++ 0x.

Ответ 7

Самый простой ответ - использовать vector<struct sb>, где sb - struct {boolean b};. Тогда вы можете сказать push_back({true}). Это кажется хорошим.

Ответ 8

Мой предпочтительный обходной путь - это vector enoped enum, который имеет базовый тип 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 );