93

第 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++ 一直没有遵循这个规范。

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

4

1 回答 1

101

这个扩展的动机,可以被符合标准的程序检测到,因此是不符合标准的,是为了让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);
}

标准规范说,标记的断言// Fires!将触发,但仅在test使用vector<bool>. 当使用 a 运行时vector<char>(或分配适当的非默认值时vector除外),测试通过。boolT

libc++ 实现试图将vector<bool>在通用代码中表现不同的负面影响最小化。它为实现这一目标所做的一件事是创建 vector<T>::const_reference一个proxy-reference,就像指定的一样vector<T>::reference,只是您不能通过它进行分配。也就是说,在 libc++ 上,vector<T>::const_reference本质上是指向 . 中的位的指针vector,而不是该位的副本。

在 libc++ 上,上述test通行证适用于vector<char>vector<bool>

以什么代价?

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

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

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

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

也就是说,事后看来bitset是 to vector<bool>(应该重命名为bit_vector-- 或其他),就像arrayto一样vector。无论我们是否在谈论 and ,这个类比都bool应该value_type成立。vectorarray

有多个 C++11 和 C++14 功能示例,它们最初是作为 libc++ 中的扩展。这就是标准的演变方式。实际展示 的积极现场经验具有强大的影响力。在更改现有规范(应该如此)时,标准人员是一群保守的人。猜测,即使你确定你的猜测是正确的,也是发展国际公认标准的冒险策略。

于 2015-08-12T19:55:07.263 回答