为什么不是vector< bool> STL容器?
斯科特·迈耶斯(Scott Meyers)书的第18项有效的STL:改善您对标准模板库的使用的50种特定方法表示避免 vector< bool>
,因为它不是STL容器和它并没有真正容纳 bool
s。
以下代码:
vector <bool> v;
bool *pb =&v[0];
不会编译,违反了STL容器的要求。
错误:
cannot convert 'std::vector<bool>::reference* {aka std::_Bit_reference*}' to 'bool*' in initialization
vector&lt; t&gt; :: operator []
返回类型应该为 t&amp;
,但是为什么这是 vector&lt; bool&gt; <
thy类型。 /代码>?
vector&lt; bool&gt;
真正由什么组成?
该项目进一步说:
deque<bool> v; // is a STL container and it really contains bools
可以用作 vector&lt; bool&gt;
的替代方案吗?
有人可以解释一下吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
出于空间优化的原因,C ++标准(回到C ++ 98)明确呼叫
vector&lt; bool&gt;
作为一个特殊的标准容器,其中每个Bool仅使用一个位置而不是一个空间字节作为正常的bool将(实现一种“动态bitset”)。为了换取此优化,它无法提供普通标准容器的所有功能和接口。在这种情况下,由于您无法在字节中稍微删除一些地址,因此
operator []
之类的东西无法返回bool&amp;
,而是返回允许操纵特定位的代理对象。由于此代理对象不是bool&amp;
,因此您无法将其地址分配给bool*
,就像您在此类操作员上呼叫的结果一样“ 容器。反过来,这意味着bool *pb =&amp; v [0];
不是有效的代码。另一方面,
Deque
没有任何这样的专业化,因此每个Bool都会采用一个字节,您可以从operator []
中获取值的地址。最后,请注意,MS标准库实现(可以说)是最佳的,因为它使用小块的大小进行Deques,这意味着将Deque用作替代品并不总是正确的答案。
For space-optimization reasons, the C++ standard (as far back as C++98) explicitly calls out
vector<bool>
as a special standard container where each bool uses only one bit of space rather than one byte as a normal bool would (implementing a kind of "dynamic bitset"). In exchange for this optimization it doesn't offer all the capabilities and interface of a normal standard container.In this case, since you can't take the address of a bit within a byte, things such as
operator[]
can't return abool&
but instead return a proxy object that allows to manipulate the particular bit in question. Since this proxy object is not abool&
, you can't assign its address to abool*
like you could with the result of such an operator call on a "normal" container. In turn this means thatbool *pb =&v[0];
isn't valid code.On the other hand
deque
doesn't have any such specialization called out so each bool takes a byte and you can take the address of the value return fromoperator[]
.Finally note that the MS standard library implementation is (arguably) suboptimal in that it uses a small chunk size for deques, which means that using deque as a substitute isn't always the right answer.
问题在于
vector&lt; bool&gt;
返回a 代理参考对象而不是真实的参考,因此C ++ 98样式代码bool * p =&amp; V [0];
不会编译。但是,如果运营商&amp;
也可以使现代C ++ 11具有auto p =&amp; v [0];
也可以进行编译。 stackoverflow.com/q/14061694/819272"> < retrongurns代理指针对象 。霍华德·辛南特(Howard Hinnant使用此类代理参考和指针时进行改进。斯科特·迈耶斯(Scott Meyers)在关于代理类。您可以走很长的路要走几乎模仿内置类型:对于任何给定的类型
t
,一对代理(例如reference_proxy&lt; t&lt; t&gt;
可以使iterator_proxy&lt; t&gt;
)在某种意义上保持一致,因为reference_proxy&lt; t&gt; :: protor&amp;()operator&amp;()
和iterator_proxy_proxy&lt; *()
是彼此的反向。但是,在某个时候,需要将代理对象映射回行为,就像
t*
或t&amp;
。对于迭代器代理,可以过载运算符 - &gt;()
并访问模板t
的接口而无需重新实现所有功能。但是,对于参考代理,您需要超载运算符。()
,并且在当前C ++中不允许使用(尽管Sebastian Redl 在BOOSTCON 2013上呈现了这样的建议 )。您可以像参考代理中的.get()
成员一样使详细的工作围绕,或在参考中实现所有t
的界面(这就是什么为vector&lt; bool&gt; :: bit_reference
),但这要么会丢失内置语法,要么介绍没有用于类型转换的内置语义的用户定义的转换(您最多可以具有一个用户 - 定义的转换每个参数)。tl; dr :no
vector&lt; bool&gt;
不是容器用C ++ 11(自动)靠近C ++ 98。The problems is that
vector<bool>
returns a proxy reference object instead of a true reference, so that C++98 style codebool * p = &v[0];
won't compile. However, modern C++11 withauto p = &v[0];
can be made to compile ifoperator&
also returns a proxy pointer object. Howard Hinnant has written a blog post detailing the algorithmic improvements when using such proxy references and pointers.Scott Meyers has a long Item 30 in More Effective C++ about proxy classes. You can come a long way to almost mimic the builtin types: for any given type
T
, a pair of proxies (e.g.reference_proxy<T>
anditerator_proxy<T>
) can be made mutually consistent in the sense thatreference_proxy<T>::operator&()
anditerator_proxy<T>::operator*()
are each other's inverse.However, at some point one needs to map the proxy objects back to behave like
T*
orT&
. For iterator proxies, one can overloadoperator->()
and access the templateT
's interface without reimplementing all the functionality. However, for reference proxies, you would need to overloadoperator.()
, and that is not allowed in current C++ (although Sebastian Redl presented such a proposal on BoostCon 2013). You can make a verbose work-around like a.get()
member inside the reference proxy, or implement all ofT
's interface inside the reference (this is what is done forvector<bool>::bit_reference
), but this will either lose the builtin syntax or introduce user-defined conversions that do not have builtin semantics for type conversions (you can have at most one user-defined conversion per argument).TL;DR: no
vector<bool>
is not a container because the Standard requires a real reference, but it can be made to behave almost like a container, at least much closer with C++11 (auto) than in C++98.vector&lt; bool&gt;
仅使用一个位以进行value(而不是8个bool []阵列,以压缩形式包含布尔值。不可能返回C ++中的一些引用,因此有一种特殊的辅助类型“ BIT Reference”,它为您提供了一个内存中某个位置的接口,并允许您使用标准运算符和铸件。vector<bool>
contains boolean values in compressed form using only one bit for value (and not 8 how bool[] arrays do). It is not possible to return a reference to a bit in c++, so there is a special helper type, "bit reference", which provides you a interface to some bit in memory and allows you to use standard operators and casts.许多人认为
vector&lt; bool&gt;
专业化是一个错误。在论文中“ noreferrer”> +17“
有一个建议
重新考虑矢量部分专业。
Many consider the
vector<bool>
specialization to be a mistake.In a paper "Deprecating Vestigial Library Parts in C++17"
There is a proposal to
Reconsider vector Partial Specialization.
查看如何实现。 STL在模板上大大构建,因此标题确实包含了它们所做的代码。
例如,查看 stdc ++ 实现在这里。
即使不是STL符合的位向量,也很有趣的是 llvm :: bitvector 来自在这里。
llvm :: bitVector
的本质是一个嵌套类,称为参考
和合适的操作员过载以使bitvector
的行为与vector相似
有一些限制。下面的代码是一个简化的界面,以显示BitVector如何隐藏一个称为Reference
的类,以使真实实现几乎像真实的Bool一样,而无需为每个值使用1个字节。此代码在这里具有不错的属性:
此代码实际上有缺陷,尝试运行:
由于
servert(((&amp; b [5] - &amp; b [3]))==(5-3) );
将失败(在llvm :: BitVector
中)这是非常简单的LLVM版本。
std :: vector&lt; bool&gt;
还在其中工作了。因此,呼叫
(auto i = b.begin(),e = b.end(); i!= e; ++ i)
将起作用。还有std :: vector&lt; bool&gt; :: const_iterator
。但是,在
std :: vector&lt; bool&gt;
中仍然存在局限性,这使得在某些情况下的行为不同。Look at how it is implemented. the STL builds vastly on templates and therefore the headers do contain the code they do.
for instance look at the stdc++ implementation here.
also interesting even though not an stl conforming bit vector is the llvm::BitVector from here.
the essence of the
llvm::BitVector
is a nested class calledreference
and suitable operator overloading to make theBitVector
behaves similar tovector
with some limitations. The code below is a simplified interface to show how BitVector hides a class calledreference
to make the real implementation almost behave like a real array of bool without using 1 byte for each value.this code here has the nice properties:
This code actually has a flaw, try to run:
will not work because
assert( (&b[5] - &b[3]) == (5 - 3) );
will fail (withinllvm::BitVector
)this is the very simple llvm version.
std::vector<bool>
has also working iterators in it.thus the call
for(auto i = b.begin(), e = b.end(); i != e; ++i)
will work. and alsostd::vector<bool>::const_iterator
.However there are still limitations in
std::vector<bool>
that makes it behave differently in some cases.这来自 http://www.cplusplus.com/reference com/reference/reference/reference/vector/vector/Vector-bool-vector-bool /
This comes from http://www.cplusplus.com/reference/vector/vector-bool/