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

How*_*ant 91 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;
    ...
Run Code Online (Sandbox Code Playgroud)

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

#include <vector>
#include <type_traits>

int
main()
{
    static_assert(std::is_same<std::vector<bool>::const_reference, bool>{}, "?");
}
Run Code Online (Sandbox Code Playgroud)

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

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

How*_*ant 98

这种扩展的动机,可以通过一致的程序检测到,因而不符合,就是使vector<bool>行为更像是vector<char>参考(const和其他).

介绍

自1998年以来,vector<bool>一直被嘲笑为"不是一个容器". LWG 96是最早的LWG问题之一,它发起了辩论.17年后的今天,vector<bool>基本保持不变.

本文讨论了一些关于行为如何vector<bool>与其他实例化不同的具体例子vector,从而损害了通用代码.然而,同一篇论文详细讨论了vector<bool>如果正确实现了非常好的性能属性.

总结: vector<bool>不是一个坏容器.它实际上非常有用.它的名字不好.

回到 const_reference

如上所述,并在此详述,不好的vector<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);
}
Run Code Online (Sandbox Code Playgroud)

标准规范表明,标记的断言// Fires!将触发,但仅在test运行时才会触发vector<bool>.当与运行vector<char>(或任何vector除了bool适当的非默认时T被分配),测试通过.

libc ++实现试图最小化vector<bool>在通用代码中具有不同行为的负面影响.它实现这一点的一件事是创建 vector<T>::const_reference一个代理引用,就像指定的那样vector<T>::reference,除了你不能通过它分配.也就是说,在libc ++上,vector<T>::const_reference本质上是指向内部位的指针vector,而不是该位的副本.

在libc ++上,上面test传递了vector<char>vector<bool>.

费用是多少?

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

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

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

这样的提议可能以新容器(例如bit_vector)的形式出现,其具有与今天相同的API vector<bool>,但是具有一些升级,例如const_reference这里讨论的.然后是vector<bool>专业化的弃用(并最终删除). bitset也可以在这个部门使用一点升级,例如add const_reference和一组迭代器.

也就是说,在事后bitsetvector<bool>(应该被重新命名为bit_vector-或其他),为arrayvector.而类比应该我们是否在谈论是成立的,boolvalue_typevectorarray.

有许多C++ 11和C++ 14特性的例子最初是作为libc ++中的扩展而开始的.这就是标准的演变过程.实际证明的 积极的实地经验具有很强的影 当涉及到改变现有规范时,标准民众是保守派(因为它们应该是这样).即使您确定自己正确猜测,猜测也是制定国际公认标准的风险策略.

  • 我的关于代理迭代器的提议草案将使`vector <bool>`符合标准的随机访问容器.它不会使`vector <bool>`成为一个好主意.:-)我同意霍华德的观点.它应该被称为其他东西. (5认同)
  • @gnzlbg:有限的经济和时间资源可用于libc ++的初始开发.随后,实施注定不会让每个用户都满意.在可用资源的情况下,进行工程权衡以试图最大化快乐用户的数量,最大化整个C++社区的利益.抱歉,您的体验.我注意到你遇到的元组扩展现在在当前的C++ 1z工作文件中.在那个问题上,你在不知不觉中牺牲了许多人可以受益,而那些人欠你的是感激之情. (5认同)