百度做的网站一般在什么后台,关键词如何排名在首页,贵州网站备案局,网站主页布局1. 基于范围的for循环语法
C11标准引入了基于范围的for循环特性#xff0c;该特性隐藏了迭代器 的初始化和更新过程#xff0c;让程序员只需要关心遍历对象本身#xff0c;其语法也 比传统for循环简洁很多#xff1a;
for ( range_declaration : range_expression )
{loo…1. 基于范围的for循环语法
C11标准引入了基于范围的for循环特性该特性隐藏了迭代器 的初始化和更新过程让程序员只需要关心遍历对象本身其语法也 比传统for循环简洁很多
for ( range_declaration : range_expression )
{loop_statement;
}
基于范围的for循环不需要初始化语句、条件表达式以及更新表 达式取而代之的是一个范围声明和一个范围表达式。其中范围声明 是一个变量的声明其类型是范围表达式中元素的类型或者元素类型 的引用。而范围表达式可以是数组或对象对象必须满足以下2个条件 中的任意一个。 1对象类型定义了begin和end成员函数。 2. 定义了以对象参数为类型的begin和end普通函数。
#include iostream
#include string
#include map
std::mapint, std::string index_map{ {1, hello}, {2, world},
{3, !} };
int int_array[] { 0, 1, 2, 3, 4, 5 };
int main()
{for (const auto e : index_map){std::cout key e.first , value e.second std::endl;}for (auto e : int_array){std::cout e std::endl;}
}
如果不会在循环过程中修改引用对象那么推荐在范围声明中加上const限定符以帮助编译器生成更加高效的代码
#include iostream
#include vectorstruct X
{X() { std::cout default ctor std::endl; }X(const X other){std::cout copy ctor std::endl;}
};int main()
{std::vectorX x(10);std::cout for (auto n : x) std::endl;for (auto n : x){}std::cout for (const auto n : x) std::endl;for (const auto n : x){}
} 2. 实现自己的range-for
//since C17, until C20for (range-declaration : range-expression )
{loop-statement
}The above syntax produces code equivalent to the following except for the lifetime expansion of temporaries of range-expression.
{auto __range range-expression ; //gcc//auto _range range-expression; //clangauto __begin begin-expr ;auto __end end-expr ;for ( ; __begin ! __end; __begin){range-declaration *__begin;loop-statement}
}
其中operator *用于编译器生成解引用代码operator !用于生成循环条件代码而前缀版本的operator 用于更新迭代器。
#include iostreamtemplatetypename T, size_t L
class Iter
{
public:Iter(T* data, size_t idx):data{data}, idx{idx}{}T operator*(){return *(data idx);}Iter operator()//前缀operator {idx;return *this;}bool operator ! (const Iter other){return other.idx ! this-idx;}private:size_t idx{0};T* data;
};templatetypename T, size_t L
class array
{
public:using iterator IterT, L;array(std::initializer_listT list){T * ptr data;for (const auto e : list){*ptr e;ptr;}}iterator begin(){return iterator(data, 0);}iterator end(){return iterator(data, L);}
private:T data[L]{};
};int main(void)
{arrayint, 4 arr{10,20,30,40};for(auto iter arr.begin(); iter ! arr.end(); iter){std::cout *iter ;}for (const auto i : arr){std::cout i ;}std::cout std::endl;
}以上代码类模板array中实现了iterator begin()和 iterator end()在迭代器类Iter中实现了operator*(), operator()[注意这里是前缀operator]以及operator!。
3. 临时范围表达式的陷阱
无论是C11还是C17基于范围的for循环伪代码
//since C17, until C20
for (range-declaration : range-expression )
{ loop-statement
}
The above syntax produces code equivalent to the following except for the lifetime expansion of temporaries of range-expression.
{ auto __range range-expression ; //gcc版本 //auto _range range-expression; //clang版本 auto __begin begin-expr ; auto __end end-expr ; for ( ; __begin ! __end; __begin) { range-declaration *__begin; loop-statement }
}
对于下面这个例子代码
#include iostream
#include vectorclass RangeFor
{
public:std::vectorint items() { return data; }
private:std::vectorint data{10, 20, 30, 40};
};RangeFor foo()
{RangeFor data;return data;
}int main(void)
{/*step 1: foo() return rvalue;step 2: items() return l_val_ref of rvalue.step 3: __range is an align for l_val_ref.step 4: rvalue(temp value) destory.now __range reference to dangling refenence.*/for (const auto x : foo().items()) //gcc: unexcepted number//clang: segmentation fault{std::cout x ;}return 0;
}
我们从C Insights分析看
#include iostream
#include vectorclass RangeFor
{public: inline std::vectorint, std::allocatorint items(){return this-data;}private: std::vectorint, std::allocatorint data;public: // inline RangeFor(RangeFor ) noexcept default;// inline ~RangeFor() noexcept default;// inline constexpr RangeFor() noexcept(false) default;
};RangeFor foo()
{RangeFor data RangeFor() /* NRVO variable */;return data;
}int main()
{{std::vectorint, std::allocatorint __range1 foo().items();__gnu_cxx::__normal_iteratorint *, std::vectorint, std::allocatorint __begin1 __range1.begin();__gnu_cxx::__normal_iteratorint *, std::vectorint, std::allocatorint __end1 __range1.end();for(; __gnu_cxx::operator!(__begin1, __end1); __begin1.operator()) {int const x __begin1.operator*();std::operator(std::cout.operator(x), );}}return 0;
}
从clang角度编译器看 std::vectorint, std::allocatorint __range1 foo().items();
foo()返回临时右值这个临时右值调用items返回了一个左值引用然后 __range有引用了这个临时右值接口items返回的左值引用这个句子结束后这个临时右值销毁了这个时候__range其实引用的是一个已经不存在对象的数据。
auto __range range-expression ;
这个是是cpp reference上说的(应该是gcc版本的)。其最终结果也是一样的我们来分析下上面那段代码
/* step 1: foo() return temp rvalue; step 2: items() return l_val_ref of rvalue. step 3: __range is an alias for l_val_ref. step 4: rvalue(temp value) destory. now __range reference to dangling refenence. */ for (const auto x : foo().items()) //gcc: unexcepted number //clang: segmentation fault { std::cout x ; }
可能这里有些人觉得 定义了const autox可以捕获临时变量这个是没错的对于这个range-for来回代码相当于如下
#include iostream
#include vector#include stringclass RangeFor
{
public:RangeFor() : data(rangeFor) { std::cout ctor std::endl; }std::string getItems(){std::cout get data std::endl;return data;}~RangeFor(){std::cout dtor std::endl;data ;}private:std::string data;
};RangeFor foo()
{RangeFor data;return data;
}int main(void)
{/*step 1: foo() return rvalue;step 2: items() return l_val_ref of rvalue.step 3: vec is an align for l_val_ref.step 4: rvalue(temp value) destory.*/const auto ret foo().getItems();//note: now vec reference to dangling refenence.if (ret.empty()){std::cout empty string std::endl;}else{std::cout ret std::endl;}return 0;
}
const auto ret foo(), getItems();这个 const左值引用ret作用于getItems返回的左值引用这个getItems返回的左值引用(打比喻是毛)的真真数据是foo(返回的临时变量(打比喻是皮)这行代码结束后临时变量被销毁了。getItems返回的左值引用用一句话总结就是皮之不存毛将焉附
4. 基于范围的for 循环的初始化
C17 引入了if 和switch 控制结构的可选初始化C20 现在为基于范围的for 循环引入了这 样一个可选的初始化。
for ( init-statement(optional); range-declaration : range-expression )
{ loop-statement
}
The above syntax produces code equivalent to the following:
{ init-statement auto __range range-expression ; auto __begin begin-expr ; auto __end end-expr ; for ( ; __begin ! __end; __begin) { range-declaration *__begin; loop-statement }
}
我们来看个代码示例
#include iostream
#include vectorclass RangeFor
{
public:std::vectorint items() { return data; }
private:std::vectorint data{10, 20, 30, 40};
};RangeFor foo()
{RangeFor data;return data;
}int main(void)
{//const auto thing foo();//for (const auto x : thing.items())// C17for (auto thing foo(); const auto x :thing.items()) //since c20{std::cout x ;}return 0;
}