ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

c – 使用`for(auto&e:cont)`是否安全?向量有什么问题?

2019-07-25 06:06:40  阅读:359  来源: 互联网

标签:c c11 auto boolean stdvector


我发现for(auto& e:cont)有时用于代替普通(auto e:cont)(其中cont是一些容器,例如std :: vector).到目前为止,我找到了两个原因:

>参考应避免复制对象(执行速度更快)
>某些类可能禁止制作副本(例如std :: thread)

经过几次测试,我可以看到:

> for(auto& e:cont)适用于任何std :: vector< T>除了std :: vector< bool>
> for(cont :: reference e:cont)适用于任何std :: vector< T>包括std :: vector< bool> (这里显而易见的问题是:
我应该使用它而不是(auto& e:cont)吗?
> std :: vector< bool>不被认为是真正的容器,许多人认为它应该被重命名(实现很好,很有用,但应该有不同的名称,如bitset或bitfield或dynamic_bitset)
> std :: vector< bool>可以以(auto& e:cont)也可以工作的方式实现(参见下面的尝试)

这是我用于测试的代码:
(诀窍是使用reference& iterator :: operator *(){return * this;})

#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;
}

问题:

>我应该使用(cont :: reference e:cont)而不是(auto& e:cont)吗?
>诀窍有什么问题?任何用例都可以增强它吗?
编辑:我指的是bvect :: reference& bvect :: iterator :: operator *(){return * this; } 这里.
>可以/应该更改STL吗? (参考vector< bool>)

反馈:答案和评论:

>使用for(auto&& e:cont)(用于写入)或用于(const auto& e:cont)(用于读取/枚举)似乎适用于所有情况. (感谢dyp和Praetorian)
>使用typename iterator_traits< decltype(begin(cont))> :: reference似乎也适用于数组(cont = boo [2]). (是的,它很难看但可以使用我认为的一些模板别名来缩短.我不能想到反例这里需要什么,所以,现在,这不是解决方案.auto&& is)
>标准说iterator :: operator *()必须返回iterator :: reference(不是iterator :: reference&),但仍然不知道为什么.

最终裁决:

auto it = bits.begin();
auto&& e = *it; cout << (bool)e;
it++; cout << (bool)e;
cout << endl;

输出:

10

这绝对是坏事.我们应该坚持使用标准(iterator :: operator *()必须返回iterator :: reference).谢谢 :)

解决方法:

矢量< BOOL&GT是矢量类模板的特化,它将布尔值存储在位域中以进行空间优化.由于您无法返回对位域的引用,因此vector< bool> :: reference是类类型,代表单个bool的代理. vector< bool> :: operator []按值返回此代理类实例;这同样适用于解除引用向量< bool> :: iterator.

vector<bool> cont;
for (auto& e : cont) { ... }

在这里,您尝试将左值引用绑定到右值,这是不允许的.

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数组.使用cont :: reference将失败,以及任何没有名为reference的成员类型的可迭代类型.如果你想只读访问循环中的容器元素,你应该使用(auto const& e:cont),如果你想修改元素,你应该使用(auto&& e:cont).

在后一种情况下,汽车&& e是一个可以绑定到左值和右值的通用引用,因此它适用于向量< bool>案件也是.

标签:c,c11,auto,boolean,stdvector
来源: https://codeday.me/bug/20190725/1530093.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有