C++ 基于范围的for循环

发布时间 2023-09-12 10:26:44作者: 冰山奇迹

C++11标准对语言引入了许多优秀的、有用的改进。我已经介绍了auto关键字,现在我再来说一下基于范围的for循环。怎样使用?怎样在你自己的类中使用?

1 基于范围的for循环的基本语法

现在,几乎每一个语言都能有一个非常方便的实现for循环的方法。C++也有类似的概念;你可以为你的for循环,添加一个container,他就会自动迭代。我们看下面的例子:

vector<int> vec;
vec.push_back(10);
vec.push_back(20);

for (int i : vec)
{
    cout << i;
}

这段代码就是实现了对于vector型变量vec的内容打印,变量i遍历vector中的每一个元素,直到vector的结束。
当然了,在这里,为了迭代更加复杂的数据结构,你可以使用auto关键字。例如,迭代一个map类型数据变量,你可以这样写:

map<string, string> address_book;
for (auto address_entry : address_book)
{
    cout << address_entry.first << " < " address_entry.second << " > " << endl;
}

编程人员就不需要担心要迭代类型的拼写了。

2 修改Vector内容

如果你想修改正在遍历的容器里的值,或者你想避免拷贝大量的对象,基本的迭代器就支持,你可以将循环变量作为引用调用。例如,对一个int型vector对象中每一个元素进行自加。

vector<int> vec;
vec.push_back(1);
vec.push_back(2);

for(int& i : vec)
{
    // 增加vector对象中元素的值
    i++;    
}

for (int i : vec)
{
    // 显示更新后的数值
    cout << i << endl;
}

3 基于范围是什么意思呢?

String,array和所有的STL容器类都能被这种新的基于范围的for循环迭代。但是,如果你将新语法应用到你自定义的数据结构上呢?
为了使一个数据具有可迭代性,他必须与STL迭代具有相似的工作属性。

  • (1)具有begin和end方法,即可以作为成员函数也可以作为独立的函数,函数返回数据结构开始和结束的迭代器。
  • (2)迭代器必须支持操作符*,!=,++,即可以作为成员函数也可作为独立函数(详细的信息可以参考操作符重载)。

在这里请注意,++操作符必须是前缀的,它被声明为不带参数的operator函数。

就是这样,用这五个函数,你就可以造一个数据结构,能够满足基于范围的for循环。但是begin()和end()方法是非成员函数(begin(container)代替container.begin()),你甚至可以为了适应已经存在的数据结构,不必刻意地支持STL类型的迭代器。你必须做的就是创建你自己的迭代器,它支持*(指针),前缀自加(++)和!=还要定义迭代器的begin和end,就可以了。

因为基于范围的循环是如此漂亮,我猜想那些不支持STL iterator的新容器类,都想添加一个适配器,去允许基于范围的for循环的。下面是一个小程序,创建一个简单的迭代器,然后实现基于范围的for循环。其中,首先创建IntVector类型,大小是100,可以被一个迭代器Iter迭代。代码如下:

// a simple iterator sample.

#include <iostream>

using namespace std;

// forward-declaration to allow use in Iter
class IntVector;

class Iter
{
private:
    int _pos;
    const IntVector *_p_vec;

public:
    Iter(const IntVector* p_vec, int pos) : _pos(pos), _p_vec(p_vec){}

    // these three methods form the basis of an iterator for use with a range-based for loop
    bool operator!=(const Iter& other) const
    {
        return _pos != other._pos;
    }

    // this method must be defined after the definition of IntVector since it needs to use it
    int operator*() const;
    const Iter& operator++()
    {
        ++_pos;
        // although not strictly necessary for a range-based for loop
        // following the normal convention of returning a value from
        // operator++ is a good idea.
        return *this;
    }
};

class IntVector
{
private:
    int _data[100];

public:
    IntVector(){}

    int get(int col) const
    {
        return _data[col];
    }

    Iter begin() const
    {
        return Iter(this, 0);
    }

    Iter end() const
    {
        return Iter(this, 100);
    }

    void set(int index, int val)
    {
        _data[index] = val;
    }
};

int Iter::operator*() const
{
    return _p_vec->get(_pos);
}

// sample usage of the range-based for loop on IntVector
int main()
{
    IntVector v;

    for(int i = 0; i < 100; i++)
    {
        v.set(i,i);
    }
    for( int i : v)
    {
        cout << i << endl;
    }
}

这段代码需要注意的是,它不允许在for循环中使用引用&,而去实现IntVector元素的修改。这很容易实现,改变get()的返回值为一个引用,但是这样做,会使代码变长,我们这里只是关注基本结构。

4 基于范围的循环增加性能吗?

用GCC4.6版本编译器测试,发现基于范围的for循环并没有比正常的STL迭代器有性能方面的提升,但是似乎跟STL的for_each函数对性能的提升是一样的,for_each函数使用了和迭代器相同的迭代模型。

5 编译器的支持度

不幸的是,基于范围的循环没有被很好滴支持。GCC4.6版本以上。

原文:C++11新特性-基于范围的for循环

C++11标准对语言引入了许多优秀的、有用的改进。我已经介绍了auto关键字,现在我再来说一下基于范围的for循环。怎样使用?怎样在你自己的类中使用?
1 基于范围的for循环的基本语法现在,几乎每一个语言都能有一个非常方便的实现for循环的方法。C++也有类似的概念;你可以为你的for循环,添加一个container,他就会自动迭代。我们看下面的例子:
vector<int> vec;vec.push_back(10);vec.push_back(20);
for (int i : vec){    cout << i;}12345678这段代码就是实现了对于vector型变量vec的内容打印,变量i遍历vector中的每一个元素,直到vector的结束。当然了,在这里,为了迭代更加复杂的数据结构,你可以使用auto关键字。例如,迭代一个map类型数据变量,你可以这样写:
map<string, string> address_book;for (auto address_entry : address_book){    cout << address_entry.first << " < " address_entry.second << " > " << endl;}12345编程人员就不需要担心要迭代类型的拼写了。
2 修改Vector内容如果你想修改正在遍历的容器里的值,或者你想避免拷贝大量的对象,基本的迭代器就支持,你可以将循环变量作为引用调用。例如,对一个int型vector对象中每一个元素进行自加。
vector<int> vec;vec.push_back(1);vec.push_back(2);
for(int& i : vec){    // 增加vector对象中元素的值    i++;    }
for (int i : vec){    // 显示更新后的数值    cout << i << endl;}1234567891011121314153 基于范围是什么意思呢?String,array和所有的STL容器类都能被这种新的基于范围的for循环迭代。但是,如果你将新语法应用到你自定义的数据结构上呢?为了使一个数据具有可迭代性,他必须与STL迭代具有相似的工作属性。
(1)具有begin和end方法,即可以作为成员函数也可以作为独立的函数,函数返回数据结构开始和结束的迭代器。(2)迭代器必须支持操作符*,!=,++,即可以作为成员函数也可作为独立函数(详细的信息可以参考操作符重载)。在这里请注意,++操作符必须是前缀的,它被声明为不带参数的operator函数。
就是这样,用这五个函数,你就可以造一个数据结构,能够满足基于范围的for循环。但是begin()和end()方法是非成员函数(begin(container)代替container.begin()),你甚至可以为了适应已经存在的数据结构,不必刻意地支持STL类型的迭代器。你必须做的就是创建你自己的迭代器,它支持*(指针),前缀自加(++)和!=还要定义迭代器的begin和end,就可以了。
因为基于范围的循环是如此漂亮,我猜想那些不支持STL iterator的新容器类,都想添加一个适配器,去允许基于范围的for循环的。下面是一个小程序,创建一个简单的迭代器,然后实现基于范围的for循环。其中,首先创建IntVector类型,大小是100,可以被一个迭代器Iter迭代。代码如下:
// a simple iterator sample.
#include <iostream>
using namespace std;
// forward-declaration to allow use in Iterclass IntVector;
class Iter{private:    int _pos;    const IntVector *_p_vec;
public:    Iter(const IntVector* p_vec, int pos) : _pos(pos), _p_vec(p_vec){}
    // these three methods form the basis of an iterator for use with a range-based for loop    bool operator!=(const Iter& other) const    {        return _pos != other._pos;    }
    // this method must be defined after the definition of IntVector since it needs to use it    int operator*() const;    const Iter& operator++()    {        ++_pos;        // although not strictly necessary for a range-based for loop        // following the normal convention of returning a value from        // operator++ is a good idea.        return *this;    }};
class IntVector{private:    int _data[100];
public:    IntVector(){}
    int get(int col) const    {        return _data[col];    }
    Iter begin() const    {        return Iter(this, 0);    }
    Iter end() const    {        return Iter(this, 100);    }
    void set(int index, int val)    {        _data[index] = val;    }};
int Iter::operator*() const{    return _p_vec->get(_pos);}
// sample usage of the range-based for loop on IntVectorint main(){    IntVector v;
    for(int i = 0; i < 100; i++)    {        v.set(i,i);    }    for( int i : v)    {        cout << i << endl;    }}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384这段代码需要注意的是,它不允许在for循环中使用引用&,而去实现IntVector元素的修改。这很容易实现,改变get()的返回值为一个引用,但是这样做,会使代码变长,我们这里只是关注基本结构。
4 基于范围的循环增加性能吗?
用GCC4.6版本编译器测试,发现基于范围的for循环并没有比正常的STL迭代器有性能方面的提升,但是似乎跟STL的for_each函数对性能的提升是一样的,for_each函数使用了和迭代器相同的迭代模型。
5 编译器的支持度
不幸的是,基于范围的循环没有被很好滴支持。GCC4.6版本以上————————————————版权声明:本文为CSDN博主「tupelo-shen」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/shenwanjiang111/article/details/59511235