它是安全使用`为(自动急症:续)`?什么是错的矢量<&布尔GT ;? [英] Is it safe to use `for(auto& e : cont)`? What is wrong with vector<bool>?

查看:118
本文介绍了它是安全使用`为(自动急症:续)`?什么是错的矢量<&布尔GT ;?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现,为(自动急症:续)有时被用来代替普通的为(自动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:


  1. 拍摄的参考,应避免复制对象(更快的执行)

  2. 进行复印,可以禁止某些类别(如的std ::线程

  1. Taking a reference should avoid copying the object (faster execution)
  2. Making a copy may be forbidden for some classes (e.g. std::thread)

在一些测试,我可以看到:

After few tests I can see:


  1. 为(自动急症:续)适用于任何的std ::矢量< T> 除了的std ::矢量<&布尔GT;

  2. 的(续::参考E:续) 的适用于任何的std ::矢量< T> 包括的std ::矢量<&布尔GT; (这里的显而易见的问题是:结果
    我倒是应该用这个来代替为(自动急症:续)

  3. 的std ::矢量<布尔> 不被认为是真正的容器中,许多人认为它应该改名(实施细而有用的,但应该有不同名称,如位集位域来,dynamic_bitset

  4. 的std ::矢量<布尔> 可以在某种程度上实现了为(自动急症:续)也行(见下面我尝试)

  1. for (auto& e : cont) works with any std::vector<T> except std::vector<bool>
  2. for (cont::reference e : cont) works with any std::vector<T> including std::vector<bool> (the obvious question here is:
    Should I rather use this instead of for (auto& e : cont)?
  3. 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 like bitset or bitfield or dynamic_bitset)
  4. std::vector<bool> can be implemented in a way that for (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:


  1. 如果我宁愿用的(续::参考E:续)而不是为(自动急症:续)

  2. 什么是错的把戏?它可以被增强,被罚款用于任何用途的情况?结果
    编辑:我指的是 bvect ::参比, bvect:迭代::运算符*(){返回*这一点; } 在这里。

  3. CAN / STL应该改变? (指的是矢量&lt;&布尔GT;

  1. Should I rather use for (cont::reference e : cont) instead of for (auto& e : cont)?
  2. What is wrong with the trick? Can it be enhanced to be fine for any use-case?
    I am refering to bvect::reference& bvect::iterator::operator * () { return *this; } here.
  3. Can/Should STL be changed? (refering to vector<bool>)

反馈:答案和评论:

FEEDBACK: Answers and Comments:


  1. 使用为(自动&安培;急症:续)(写入)或的(常量自动急症:续)(读/枚举),似乎在所有情况下工作。 (感谢去DYP和禁卫军)

  2. 使用类型名称iterator_traits&LT; decltype(开始(续))&GT; ::参考似乎甚至阵列工作(续=嘘[2])。 (是的,这是丑陋的,但可以使用一些模板别名,我认为可以缩短我想不出反例,但这样做需要的,所以,就目前而言,这不是解决办法汽车和放大器;&放; 是)

  3. 标准说, ::迭代器的operator *()必须返回迭代器::参考(不是迭代器::参比,),但仍然不知道为什么

  1. Using for (auto&& e : cont) (for writing) or for (const auto& e : cont) (for reading/enumerating) seems to work in all cases. (Thanks go to dyp and Praetorian)
  2. 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)
  3. Standard says that iterator::operator * () have to return iterator::reference (not iterator::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 of for (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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆