运算符 |= std::vector<bool>

operator |= on std::vector<bool>

以下代码无法编译

#include <vector>
int main()
{
  std::vector<bool> enable(10);
  enable[0] |= true;
  return 0;
}

报错

no match for ‘operator|=’ (operand types are ‘std::vector<bool>::reference {aka std::_Bit_reference}’ and ‘bool’)

在我的实际代码中,我有一个位字段,其中包含我想要 |= 函数结果的值。

有很简单的方法可以表达相同的想法,但是有什么好的理由不提供这样的运算符吗?

你为什么不做下面的事情呢?

enable[0] = enable[0] | true;

你应该可以很容易地自己制作一个。类似于:

std::vector<bool>::reference& operator |= (std::vector<bool>::reference& a, bool b)
{
    if (b)
       a = true;
    return a;
}

或者,std::bitset 很合适。

主要原因是 std::vector<bool> 是特殊的,其规范明确允许实现最小化内存使用。

对于除 bool 之外的任何向量,引用类型实际上可以是真正的引用(即 std::vector<int>::reference 实际上可以是 int &)——通常直接引用的元素矢量本身。因此,引用类型支持基础类型可以支持的所有操作是有意义的。这是有效的,因为 vector<int> 在内部有效地管理了一个连续的 int 数组。除了 bool.

之外的所有类型也是如此

但是,为了尽量减少内存使用,std::vector<bool> 可能不会(实际上可能不会)在内部与实际的 bool 数组一起工作。相反,它可能会使用一些压缩数据结构,例如内部的 unsigned char 数组,其中每个 unsigned char 是一个包含 8 位的位域。因此,长度为 800 的 vector<bool> 实际上会管理一个 100 unsigned char 数组,它消耗的内存将是 100 字节(假设没有过度分配)。如果 vector<bool> 实际上包含一个 800 bool 的数组,它的内存使用量将至少为 800 字节(因为 sizeof(bool) 必须至少为 1,根据定义)。

为了允许 vector<bool> 的实现者进行此类内存优化,vector<bool>::operator[] 的 return 类型(即 std::vector<bool>::reference)不能简单地是 bool &。在内部,它可能包含对基础类型的引用(例如 unsigned char)和跟踪它实际影响的位的信息。这将使所有 op= 运算符(+=-=|= 等)在基础类型上的操作有些昂贵(例如位摆弄)。

std::vector<bool> 的设计者将面临

之间的选择
  1. 指定std::vector<bool>::reference支持所有 op= 并不断听到关于运行时效率低下的抱怨 使用这些运算符的程序员

  2. 不支持那些认为这些事情没问题的程序员=和现场投诉("cleaner code"等),即使它们效率低下。

看来 std::vector<bool> 的设计者选择了选项 2。结果是 std::vector<bool>::reference 支持的唯一赋值运算符是常用标准 operator=()(操作数为reference,或类型 bool) 不是任何操作 =。这种选择的优点是,如果程序员试图做一些在实践中实际上是糟糕选择的事情,就会出现编译错误。

毕竟,尽管 bool 支持所有操作 = 使用它们并没有取得多大的成就。例如,some_bool |= truesome_bool = true 具有相同的净效果。

简短而甜蜜的回答:std::vector<bool> 应该避免。请改用 vector<wchar>。你实际上得到了一个容器,其中 bools 被打包成位,这给出了与其他向量不同的行为,缓慢的代码并且没有人关心内存。我想现在没有人喜欢这个了,但时光倒流会破坏太多代码...