第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 ++一直没有遵循这个规范。
这种不合规的动机是什么?
答案 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 here,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>
一起运行时才会触发。如果在分配了适当的非默认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
)的形式出现,其容量与今天vector<bool>
的API大致相同,但有一些升级,例如{ {1}}在这里讨论。随后是const_reference
专业化的弃用(并最终删除)。 vector<bool>
也可以在此部门使用一点升级,例如添加bitset
和一组迭代器。
也就是说,事后看来const_reference
是bitset
(应该重命名为vector<bool>
- 或其他),因为bit_vector
是array
。无论我们是否将vector
作为bool
value_type
和vector
进行讨论,这个类比都应该成立。
C ++ 11和C ++ 14功能有多个例子,它们最初是libc ++中的扩展。这就是标准的演变过程。实际演示 积极现场体验具有强大影响力。当涉及到改变现有规范时,标准民众是保守派(因为它们应该是这样)。即使您确定自己正确猜测,猜测也是制定国际公认标准的风险策略。