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

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

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

这个扩展的动机可以通过一致性程序来检测,因此不符合,就是使vector<bool>对于引用(const和otherwise)的行为更像vector<char>

介绍

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

本文将介绍vector<bool>vector每个实例的不同之处,从而影响generics代码。 然而,同样的文章详细讨论了如果正确实现,非常好的性能属性vector<bool>

总结vector<bool>不是一个糟糕的容器。 这实际上非常有用。 它只是一个坏名字。

回到const_reference

正如上面介绍的, 这里详细介绍的, vector<bool>有什么不好的地方在于,它在generics代码中的performance与其他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> (或者当一个合适的非默认T被分配时,除了bool之外的任何vector ),testing通过。

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

在libc ++上面的test通过了vector<char>vector<bool>

在什么成本?

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

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

为了使libc ++客户端在generics代码中有更好的行为,也许在经过充分的现场testing之后,为了改进整个C ++行业,将这个扩展推荐给未来的C ++标准。

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

也就是说,在事后bitsetvector<bool> (应该重命名为bit_vector – 或其他),因为arrayvector 。 无论我们是否将bool作为vectorarray ,这个类比应该是真实的。

C ++ 11和C ++ 14的许多function都是以libc ++的扩展名开始的。 这是标准如何演变的。 实际performance 积极的实地经验产生强烈的影响 对于改变现有的规范(他们应该是这样),标准的人是保守的。 猜测,即使你确定你猜对了,对于发展一个国际公认的标准来说,这是一个冒险的策略。