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

Как (надеюсь) мы все знаем, vector<bool> полностью сломан и не может рассматриваться как массив переменного тока. Каков наилучший способ получить эту функциональность? До сих пор я думал о следующих идеях:

  • Использовать vector<char> вместо или
  • Используйте класс-оболочку и vector<bool_wrapper>

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

В качестве дополнительного вопроса, если мне не нужен метод c_array(), каков наилучший способ решения этой проблемы, если мне нужен произвольный доступ? Должен ли я использовать deque или что-то еще?

Редактировать:

  • Мне нужен динамический размер.
  • Для тех, кто не знает, vector<bool> специализируется так, что каждый бул занимает 1 бит. Таким образом, вы не можете преобразовать его в массив в стиле c.
  • Я думаю, что "обертка" является немного неправильным. Я думал что-то вроде этого:

Конечно, тогда я должен прочитать в my_bool из-за возможных проблем с выравниванием:(

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

8 ответов

Решение

Использование 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 * 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 и конструкторами копирования по умолчанию. Я добавил сортировку, чтобы убедиться, что она реагирует так, как предполагалось при использовании алгоритмов.

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

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

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

boost::container::vector<bool>:

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

...

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

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

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

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

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

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

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

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

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

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

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