赞
踩
“Executes a for loop over a range.Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container.”
是个啥大家都了解
就是用迭代器遍历一个容器(就是用迭代器遍历一个容器)
for ( range_declaration : range_expression ) loop_statement
code | description |
---|---|
range_declaration | a declaration of a named variable, whose type is the type of the element of the sequence represented by range_expression, or a reference to that type. Often uses the auto specifier for automatic type deduction |
range_expression | any expression that represents a suitable sequence (either an array or an object for which begin and end member functions or free functions are defined, see below) or a braced-init-list. |
loop_statement | any statement, typically a compound statement, which is the body of the loop |
主要分为三部分
std::vector<int> numbers = {1,2,3,4,5};
for (auto n: numbers)
{
std::cout<<n;
}
用起来挺简单的吧
接下来我们把 Range-based for loop的实现展开
{
auto && __range = range_expression ;
auto __begin = begin_expr ;
auto __end = end_expr ;
for ( ; __begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}
上面3的例子给它展开
{
std::vector<int, std::allocator<int> > & __range1 = numbers;
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > __begin1 = __range1.begin();
__gnu_cxx::__normal_iterator<int *, std::vector<int, std::allocator<int> > > __end1 = __range1.end();
for(; __gnu_cxx::operator!=(__begin1, __end1); __begin1.operator++()) {
int n = __begin1.operator*();
std::cout.operator<<(n);
}
}
好像也没哈 看起来就是用个迭代器去访问里边的元素
可是外边为啥包个大括号?
__range 为啥是个右值引用呢?
精髓来了。它就是这段话
If range_expression returns a temporary, its lifetime is extended until the end of the loop, as indicated by binding to the forwarding reference __range, but beware that the lifetime of any temporary within range_expression is not extended.
为什么要这么搞呢?
- 试想一下,如果range_expression是一个函数返回的临时对象,那么 __range 就可以引用这个对象,并将其生命周期延长到外层包的的括号内。这样使用右值引用不仅减少了变量的拷贝,同时最外层的大括号也保证了生命周期。
看起来是个不错的语法糖
可接下要看个坑
看下面代码
std::vector<std::vector<std::string>> func() {
return {{“lebron”, "MVP"}, {“lakers, “champion”}};
}
auto strs = func().at(0);
for (auto str : strs) {
cout << str; // lebronMVP
}
for (auto str : func().at(0)) {
cout << str;//null
}
std::vector<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > >, std::allocator<std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > > strs = func(); { std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > & __range1 = strs.at(0);!!! __gnu_cxx::__normal_iterator<std::basic_string<char> *, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > __begin1 = __range1.begin(); __gnu_cxx::__normal_iterator<std::basic_string<char> *, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > __end1 = __range1.end(); for(; __gnu_cxx::operator!=(__begin1, __end1); __begin1.operator++()) { std::basic_string<char> str = std::basic_string<char>(__begin1.operator*()); std::operator<<(std::cout, str); } } { std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > & __range1 = func().at(0);!!!!! __gnu_cxx::__normal_iterator<std::basic_string<char> *, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > __begin1 = __range1.begin(); __gnu_cxx::__normal_iterator<std::basic_string<char> *, std::vector<std::basic_string<char>, std::allocator<std::basic_string<char> > > > __end1 = __range1.end(); for(; __gnu_cxx::operator!=(__begin1, __end1); __begin1.operator++()) { std::basic_string<char> str = std::basic_string<char>(__begin1.operator*()); std::operator<<(std::cout, str); } }
关键在于__range1 所引用变量的生命周期,
第一个for 中& __range1 = strs.at(0); 引用的是一个局部变量 str 的第一个数据块,它的生命周期大于for的循环体所以可以正常遍历。
可是第二个for中& __range1 = func().at(0); 引用的是fun函数返回的临时变量的第一个数据块,这个数据块虽然试图被__range1的引用延长生命周期到for的大括号内,可是函数返回的临时变量已经被销毁了,其数据块自然也被release了,所以也就没法遍历了。
而在C++ 20中准备了,
如下:
对于c++17
for (auto& x : foo().items()) { /* .. */ } // undefined behavior if foo() returns by value
在c++ 20 中增加了 Init-statement
for ( init-statement(optional)range_declaration : range_expression )loop_statement
for (T thing = foo(); auto& x : thing.items()) { /* ... */ } // OK (since C++20)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。