为什么libc ++的vector <bool> :: const_reference不是bool?

时间:2015-08-12 19:55:07

标签: c++ vector c++-standard-library libc++ std-bitset

第23.3.7节vector<bool> [vector.bool],第1段规定:

template <class Allocator> class vector<bool, Allocator> {
public:
    // types:
    typedef bool              const_reference;
    ...

但是当使用libc ++时,该程序无法编译:

#include <vector>
#include <type_traits>

int
main()
{
    static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}

此外,我注意到C ++标准在本规范中一直与C ++ 98一致。我还注意到自从第一次引入libc ++以来,libc ++一直没有遵循这个规范。

这种不合规的动机是什么?

1 个答案:

答案 0 :(得分:98)

这个扩展的动机,可以通过一致的程序检测到,因而不符合,是使vector<bool>在引用(const和其他)方面更像vector<char>。< / p>

<强>简介

自1998年以来,vector<bool>被嘲笑为“不是一个容器。”#34; LWG 96是最初的LWG问题之一,发起了辩论。 17年后的今天,vector<bool>基本保持不变。

This paper进入了一些具体的例子,说明vector<bool>的行为与vector的每个其他实例的不同,从而损害了通用代码。然而,同一篇论文详细讨论了如果正确实现了非常好的性能属性vector<bool>

摘要vector<bool>不是一个坏容器。它实际上非常有用。它的名字不好。

返回const_reference

如上所述,detailed herevector<bool>的不良之处在于它在通用代码中的行为与其他vector实例不同。这是一个具体的例子:

#include <cassert>
#include <vector>

template <class T>
void
test(std::vector<T>& v)
{
    using const_ref = typename std::vector<T>::const_reference;
    const std::vector<T>& cv = v;
    const_ref cr = cv[0];
    assert(cr == cv[0]);
    v[0] = 1;
    assert(true == cv[0]);
    assert(cr == cv[0]);  // Fires!
}

int
main()
{
    std::vector<char> vc(1);
    test(vc);
    std::vector<bool> vb(1);
    test(vb);
}

标准规范表明标记为// Fires!的断言将触发,但仅当testvector<bool>一起运行时才会触发。如果在分配了适当的非默认vector<char>时使用vector(或除bool之外的任何T运行,则测试通过。

libc ++实现试图最小化vector<bool>在通用代码中表现不同的负面影响。它实现此目的的一件事是使vector<T>::const_reference成为代理参考,就像指定的vector<T>::reference一样,除了您无法通过它进行分配。也就是说,在libc ++上,vector<T>::const_reference本质上是指向vector内部位的指针,而不是该位的副本。

在libc ++上,testvector<char>的上述vector<bool>次传递。

付出什么代价?

缺点是这个扩展是可检测的,如问题所示。但是,很少有程序真正关心这个别名的确切类型,更多的程序关心这个行为。

  

这种不合规的动机是什么?

为了给通用代码中的libc ++客户端提供更好的行为,并且可能在经过充分的现场测试之后,将此扩展建议用于未来的C ++标准,以改善整个C ++行业。

这样的提案可能会以新容器(例如bit_vector)的形式出现,其容量与今天vector<bool>的API大致相同,但有一些升级,例如{ {1}}在这里讨论。随后是const_reference专业化的弃用(并最终删除)。 vector<bool>也可以在此部门使用一点升级,例如添加bitset和一组迭代器。

也就是说,事后看来const_referencebitset(应该重命名为vector<bool> - 或其他),因为bit_vectorarray 。无论我们是否将vector作为bool value_typevector进行讨论,这个类比都应该成立。

C ++ 11和C ++ 14功能有多个例子,它们最初是libc ++中的扩展。这就是标准的演变过程。实际演示 积极现场体验具有强大影响力。当涉及到改变现有规范时,标准民众是保守派(因为它们应该是这样)。即使您确定自己正确猜测,猜测也是制定国际公认标准的风险策略。