它是安全使用`为(自动急症:续)`?什么是错的矢量&lt;&布尔GT ;? [英] Is it safe to use `for(auto& e : cont)`? What is wrong with vector<bool>?
问题描述
我发现,为(自动急症:续)
有时被用来代替普通的为(自动E:续)
(其中续
是一些容器,例如的std ::矢量
)。我发现两个原因至今:
I have found that for (auto& e : cont)
is sometimes used instead of ordinary for (auto e : cont)
(where cont
is some container, e.g. std::vector
). I have found two reasons for it so far:
- 拍摄的参考,应避免复制对象(更快的执行)
- 进行复印,可以禁止某些类别(如
的std ::线程
)
- Taking a reference should avoid copying the object (faster execution)
- Making a copy may be forbidden for some classes (e.g.
std::thread
)
在一些测试,我可以看到:
After few tests I can see:
-
为(自动急症:续)
适用于任何的std ::矢量&lt; T&GT;
除了的std ::矢量&lt;&布尔GT;
- 的
的(续::参考E:续)
的适用于任何的std ::矢量&lt; T&GT;
包括的std ::矢量&lt;&布尔GT;
(这里的显而易见的问题是:结果
我倒是应该用这个来代替为(自动急症:续)
? -
的std ::矢量&lt;布尔&GT;
不被认为是真正的容器中,许多人认为它应该改名(实施细而有用的,但应该有不同名称,如位集
或位域
或来,dynamic_bitset
) -
的std ::矢量&lt;布尔&GT;
可以在某种程度上实现了为(自动急症:续)
也行(见下面我尝试)
for (auto& e : cont)
works with anystd::vector<T>
exceptstd::vector<bool>
for (cont::reference e : cont)
works with anystd::vector<T>
includingstd::vector<bool>
(the obvious question here is:
Should I rather use this instead offor (auto& e : cont)
?std::vector<bool>
is not considered to be real container and many think that it should be renamed (the implementation is fine and usefull, but should have different name likebitset
orbitfield
ordynamic_bitset
)std::vector<bool>
can be implemented in a way thatfor (auto& e : cont)
would work as well (see my attempts below)
这里是code我已经用于测试:的结果
(诀窍是使用参比,迭代::运算符*(){返回*本;}
)
#include <vector>
#include <iostream>
#include <typeinfo>
using namespace std;
#define USE_STD_VECT_BOOL 0
#if USE_STD_VECT_BOOL
typedef vector<bool> BITS;
#else
typedef class bvect {
unsigned data; // we could use vector<unsigned> but this is just an examle
unsigned size;
public:
bvect(): data(0), size(0) {}
void push_back(bool value) {
if(value) data |= (1u<<size);
size++; }
class reference {
friend class bvect;
protected:
unsigned& data;
unsigned flag;
reference(unsigned& data, unsigned flag)
: data(data), flag(flag) {}
public:
operator bool() const {
return data & flag; }
reference& operator = (bool value) {
if(value) data |= flag;
else data &= ~flag;
return *this; }
};
class iterator: protected reference {
friend class bvect;
iterator(unsigned& data, unsigned flag)
: reference(data, flag) {}
public:
typedef bool value_type;
typedef bvect::reference reference;
typedef input_iterator_tag iterator_category;
// HERE IS THE TRICK:
reference& operator * () {
return *this; }
iterator& operator ++ () {
flag <<= 1;
return *this; }
iterator operator ++ (int) {
iterator tmp(*this);
operator ++ ();
return tmp; }
bool operator == (const iterator& rhs) {
return flag == rhs.flag; }
bool operator != (const iterator& rhs) {
return flag != rhs.flag; }
};
iterator begin() {
return iterator(data, 1); }
iterator end() {
return iterator(data, 1<<size); }
} BITS;
#endif
int main() {
BITS bits;
bits.push_back(0);
bits.push_back(1);
#if !USE_STD_VECT_BOOL
// won't compile for vector<bool>
for(auto& a : bits)
cout << typeid(a).name()
<< " = " << (int)(bool)a
<< endl;
#endif
// std::_Bit_Reference
for(BITS::reference a : bits)
cout << typeid(a).name()
<< " = " << (int)(bool)a
<< endl;
// few more tests
for(auto a : bits)
cout << (int)(bool)a;
for(bool a : bits)
cout << (int)(bool)a;
cout << endl;
}
的问题:的
Questions:
- 如果我宁愿用
的(续::参考E:续)
而不是为(自动急症:续)
? - 什么是错的把戏?它可以被增强,被罚款用于任何用途的情况?结果
编辑:我指的是bvect ::参比, bvect:迭代::运算符*(){返回*这一点; }
在这里。 - CAN / STL应该改变? (指的是
矢量&lt;&布尔GT;
)
- Should I rather use
for (cont::reference e : cont)
instead offor (auto& e : cont)
? - What is wrong with the trick? Can it be enhanced to be fine for any use-case?
I am refering tobvect::reference& bvect::iterator::operator * () { return *this; }
here. - Can/Should STL be changed? (refering to
vector<bool>
)
反馈:答案和评论:的
FEEDBACK: Answers and Comments:
- 使用
为(自动&安培;急症:续)
(写入)或的(常量自动急症:续)
(读/枚举),似乎在所有情况下工作。 (感谢去DYP和禁卫军) - 使用
类型名称iterator_traits&LT; decltype(开始(续))&GT; ::参考
似乎甚至阵列工作(续=嘘[2])。 (是的,这是丑陋的,但可以使用一些模板别名,我认为可以缩短我想不出反例,但这样做需要的,所以,就目前而言,这不是解决办法汽车和放大器;&放;
是) - 标准说,
::迭代器的operator *()
必须返回迭代器::参考
(不是迭代器::参比,
),但仍然不知道为什么
- Using
for (auto&& e : cont)
(for writing) orfor (const auto& e : cont)
(for reading/enumerating) seems to work in all cases. (Thanks go to dyp and Praetorian) - Using
typename iterator_traits<decltype(begin(cont))>::reference
seems to work even for arrays (cont=boo[2]). (Yes, it is ugly but could be shortened using some template alias I think. I cannot think of counter-example where this would be needed, so, for now, this is not the solution.auto&&
is) - Standard says that
iterator::operator * ()
have to returniterator::reference
(notiterator::reference&
), but still no clue why.
做出终审判决:的
Final Verdict:
auto it = bits.begin();
auto&& e = *it; cout << (bool)e;
it++; cout << (bool)e;
cout << endl;
输出:
10
这肯定是不好的。我们应该用标准棒( ::迭代器的operator *()
必须返回迭代器::参考
)。 谢谢:)的
This is definitely bad. We should stick with the standard (iterator::operator * ()
have to return iterator::reference
). Thank you :)
推荐答案
矢量&lt;布尔&GT;
是载体的特
存储的布尔在空间优化位域模板。因为你不能引用返回一个位域,矢量&lt;布尔&GT; ::参考
是一个类类型,即重新presents一个布尔
。 矢量&lt;&布尔GT; ::运算符[]
返回由值这个代理类实例;这同样适用于废弃一个矢量&lt;布尔方式&gt;:迭代
vector<bool>
is a specialization of the vector
class template that stores the booleans in a bitfield for space optimization. Since you cannot return a reference to a bitfield, vector<bool>::reference
is a class type, a proxy that represents a single bool
. vector<bool>::operator[]
returns this proxy class instance by value; the same applies to dereferencing a vector<bool>::iterator
.
vector<bool> cont;
for (auto& e : cont) { ... }
在这里,我们试图绑定一个左值引用一个右值,这是不允许的。
Here you're attempting to bind an lvalue reference to an rvalue, which is not allowed.
我应该还是用的(续::参考E:续)
而不是为(自动急症:续)
?
什么是错的把戏?它可以被增强,被罚款用于任何用途的情况?
Should I rather use
for (cont::reference e : cont)
instead offor (auto& e : cont)
?
What is wrong with the trick? Can it be enhanced to be fine for any use-case?
有关的好处了一系列基于的是,它适用于一个普通的C数组了。使用续::参考
将失败的,以及不具有名为成员类型的任何类型的可迭代参考
。您应该使用为(自动常量急症:续)
如果你想只读到内环路容器元素的访问权限,而为(自动&安培;急症:续)
如果要修改的元素
The nice thing about a range-based for is that it works for a plain C array too. Using cont::reference
will fail for those, as well as any iterable type that doesn't have a member type named reference
. You should use for(auto const& e : cont)
if you want read only access to the container elements within the loop, and for(auto&& e : cont)
if you want to modify the elements.
在后一种情况下,汽车和放大器;&安培; Ë
是通用参考的可以绑定到左值和右值,因此它可以在矢量&lt;布尔&GT;
情况了。
In the latter case, auto&& e
is a universal reference that can bind to lvalues and rvalues, so it works in the vector<bool>
case too.
这篇关于它是安全使用`为(自动急症:续)`?什么是错的矢量&lt;&布尔GT ;?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!