【问题标题】:Alternative to vector<bool>替代向量<bool>
【发布时间】:2010-10-14 19:02:59
【问题描述】:

正如(希望)我们都知道,vector&lt;bool&gt; 已完全损坏,不能被视为 C 数组。获得此功能的最佳方法是什么? 到目前为止,我想到的想法是:

  • 改用vector&lt;char&gt;,或者
  • 使用包装类并拥有vector&lt;bool_wrapper&gt;

你们如何处理这个问题?我需要c_array() 功能。

作为一个附带问题,如果我不需要 c_array() 方法,如果我需要随机访问,解决此问题的最佳方法是什么?我应该使用双端队列还是其他什么?

编辑:

  • 我确实需要动态调整大小。
  • 对于那些不知道的人,vector&lt;bool&gt; 是专门的,因此每个 bool 占用 1 位。因此,您不能将其转换为 C 样式的数组。
  • 我猜“包装”有点用词不当。我在想这样的事情:

当然,由于可能的对齐问题,我必须阅读my_bool :(

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

【问题讨论】:

  • 有什么理由不使用... C 风格的数组吗?
  • rlbond,你需要动态尺寸吗?
  • 好吧,我来咬一口 - 为什么你认为 vector 是“完全坏掉的”?
  • 有趣的是,vector&lt;bool&gt; 只是在我的代码中引起了数据竞争错误,因为我希望不同的线程能够安全地同时修改向量中的不同元素。使用deque&lt;bool&gt;解决。

标签: c++ stl vector boolean


【解决方案1】:

这是一个有趣的问题。

如果您需要 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 运算符和这里的默认复制构造函数完成的。 我添加了一种排序,以确保它在使用算法时做出假设。

不确定它是否适合所有情况。如果它适合您的需求,它会比重写一个类似矢量的类更少工作......

【讨论】:

  • "我们可以添加 bool* operator & () { return &m_value; }" - 错误。 ISO:“sizeof(bool) 不需要是 1
  • 我宁愿简单地将operator bool() const 更改为operator bool&amp;()。这使它更好地反映了简单 bool 的行为,因为它支持赋值等。在诸如 v[0] = true; 之类的情况下,我真的看不出此更改有问题,所以我可以进行编辑吗?
【解决方案2】:

我首选的解决方法是vector 的作用域枚举,其基础类型为bool。这非常接近如果委员会没有专门化它,我们将拥有的vector&lt;bool&gt;

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

【讨论】:

    【解决方案3】:

    这个问题已经在 comp.lang.c++.moderated 上的 discussed。建议的解决方案:

    • 您自己的分配器(基于std::allocator)和自己的向量专业化;
    • 使用 std::deque(早在 S. Mayers 的一本书中就推荐过)——但这不符合您的要求;
    • 制作 POD bool 包装器;
    • 使用与bool 大小相同的东西(char/int/etc)代替bool

    我也很早就看到了标准委员会的提案 - 引入宏(类似于 STD_VECTOR_BOOL_SPECIAL)以禁止这种专业化 - 但 AFAIK 这个提案没有在 stl 实现中实现,也没有被批准。

    看来你的问题没有办法很好地做到这一点......也许在 C++0x 中。

    【讨论】:

      【解决方案4】:

      最简单的答案是使用vector&lt;struct sb&gt;,其中sbstruct {boolean b};。然后你可以说push_back({true})。看起来不错。

      【讨论】:

        【解决方案5】:

        如果您不需要数组,请使用std::deque,是的。

        否则,请使用不专门针对 bool 的替代 vector,例如 Boost Container 中的那个。

        【讨论】:

          【解决方案6】:

          你们是如何处理这个问题的?我需要 c_array() 功能。

          boost::container::vector&lt;bool&gt;:

          vectorbool> 专业化一直存在很大问题,并且有几次不成功的尝试从标准中弃用或删除它。 Boost.Container 没有实现它,因为有一个优越的 Boost.DynamicBitset 解决方案。

          ...

          所以 boost::container::vector::iterator 返回真正的布尔引用并作为完全兼容的容器工作。如果您需要 boost::container::vectorbool> 功能的内存优化版本,请使用 Boost.DynamicBitset

          【讨论】:

            【解决方案7】:

            考虑使用向量。一旦您通过了编译和类型检查,bool 和 int 都只是机器字(编辑:显然这并不总是正确的;但在许多 PC 架构上都是正确的)。如果您想在没有警告的情况下进行转换,请使用“bool foo = !!bar”,它将零转换为假,非零转换为真。

            矢量 或类似的将使用更少的空间,尽管在某些情况下它也有可能(非常小的)速度受到影响,因为字符小于机器字长。我相信,这是使用整数而不是字符来实现布尔值的主要原因。

            如果你真的想要干净的语义,我也喜欢创建你自己的布尔类的建议——看起来像布尔,行为像布尔,但欺骗了模板专业化。

            另外,欢迎加入希望从 C++ 标准中删除向量 专业化(用 bit_vector 代替它)的人的俱乐部。这是所有酷孩子们闲逛的地方:)。

            【讨论】:

              【解决方案8】:

              取决于您的需求。我会选择std::vector&lt;unsigned char&gt;。如果您只使用功能的子集,编写包装器可能会很好,否则它将成为一场噩梦。

              【讨论】:

              • unsigned char 始终是单个字节,而实现可能不支持 uint8_tuint_fast8_t 可以工作,但如果意图明确它是一个字节而不是字符,但你也可以使用 std::byte 然后
              猜你喜欢
              • 2016-02-10
              • 2013-07-16
              • 1970-01-01
              • 1970-01-01
              • 2019-02-20
              • 2015-12-26
              • 2014-09-19
              • 2019-04-18
              相关资源
              最近更新 更多