向量<bool>::运算符[] 不当行为?

vector<bool>::operator[] misbehavior?

本文关键字:不当行为 gt lt bool 向量 运算符      更新时间:2023-10-16

可能的重复项:
为什么vector::reference不返回对bool的引用?

我曾经认为,通过std::vector::operator[]我们可以获得所访问项目的深层副本,但似乎并不总是如此。至少,对于vector<bool>,以下测试代码会给出不同的结果:

#include <iostream>
#include <vector>
using namespace std;
template <typename T>
void Test(const T& oldValue, const T& newValue, const char* message)
{
    cout << message << 'n';
    vector<T> v;
    v.push_back(oldValue);
    cout << " before:  v[0] = " << v[0] << 'n';
    // Should be a deep-copy (?)       
    auto x = v[0];   
    x = newValue;
    cout << " after:   v[0] = " << v[0] << 'n';
    cout << "-------------------------------n";
}
int main()
{
    Test<int>(10, 20, "Testing vector<int>");
    Test<double>(3.14, 6.28, "Testing vector<double>");
    Test<bool>(true, false, "Testing vector<bool>");
}

输出(使用 VC10/VS2010 SP1 编译的源代码):

Testing vector<int>
 before:  v[0] = 10
 after:   v[0] = 10
-------------------------------
Testing vector<double>
 before:  v[0] = 3.14
 after:   v[0] = 3.14
-------------------------------
Testing vector<bool>
 before:  v[0] = 1
 after:   v[0] = 0
-------------------------------

我本以为x = newValue赋值后的v[0]仍然等于其先前的值,但这似乎不是真的。为什么?为什么vector<bool>特别?

vector<bool>是一个可怕的可憎和特殊的东西。委员会专门将其用于打包位,因此它不支持正确的引用语义,因为您无法引用位,这意味着它具有不符合要求的接口,并且实际上不符合标准容器的条件。大多数人使用的解决方案只是 永远不要使用vector<bool> .

vector<bool>::operator[]既不产生bool,也不产生对bool的引用。它只返回一个充当引用的小代理对象。这是因为没有对单个位的引用,vector<bool>实际上以压缩方式存储bool。因此,通过使用auto您只是创建了该类似引用的对象的副本。问题是C++不知道这个对象充当参考。您必须通过将auto替换为T来强制"衰减到一个值"。

operator[]T的每个值返回一个T&,除了bool,它给出了一个引用代理。请参阅Herb Sutter的这个旧专栏,了解为什么在通用代码中使用vector<bool>是一个坏主意(以及为什么它甚至不是一个容器)。斯科特·迈耶斯(Scott Meyers)在Effective STL中还有一个关于它的特殊项目,在SO这里有很多关于它的问题。