Dan*_*ger 33 c++ templates c++11
我发现自己最近越来越多地使用C++ 11,而且过去我会使用迭代器,我现在尽可能使用基于范围的for循环:
std::vector<int> coll(10);
std::generate(coll.begin(), coll.end(), []() { return rand(); } );
Run Code Online (Sandbox Code Playgroud)
C++ 03:
for (std::vector<int>::const_iterator it = coll.begin(); it != coll.end(); ++it) {
foo_func(*it);
}
Run Code Online (Sandbox Code Playgroud)
C++ 11:
for (auto e : coll) { foo_func(e); }
Run Code Online (Sandbox Code Playgroud)
但是,如果集合元素类型是模板参数呢?foo_func()
可能会重载以通过const引用传递复杂(=昂贵的复制)类型,并通过值传递简单的类型:
foo_func(const BigType& e) { ... };
foo_func(int e) { ... };
Run Code Online (Sandbox Code Playgroud)
当我使用上面的C++ 03风格的代码时,我没有多想.我会以相同的方式迭代,因为取消引用const_iterator会产生一个const引用,一切都很好.但是使用C++ 11基于范围的for循环,我需要使用const引用循环变量来获得相同的行为:
for (const auto& e : coll) { foo_func(e); }
Run Code Online (Sandbox Code Playgroud)
突然间我不再确定了,如果这auto
是一个简单的类型(例如实现引用的幕后指针),这将不会引入不必要的汇编指令.
但是编译示例应用程序确认了简单类型没有开销,这似乎是在模板中使用基于范围的for循环的通用方法.如果不是这种情况,那么boost :: call_traits :: param_type就是这样的.
问题:标准中是否有任何保证?
(我意识到这个问题与基于范围的for循环并不真正相关.当使用const_iterators时它也存在.)
Die*_*ühl 13
标准容器都返回来自迭代器的引用(但是,请注意,某些"容器实际上不是容器,例如,std::vector<bool>
返回代理).其他迭代器可能会返回代理或值,尽管这不是严格支持的.
当然,该标准对性能没有任何保证.任何与性能相关的特性(超出复杂性保证)都被认为是实施质量.
也就是说,您可能需要考虑让编译器像以前一样为您做出选择:
for (auto&& e: coll) { f(e); }
Run Code Online (Sandbox Code Playgroud)
这里的主要问题是f()
可能会收到非const
参考.如果需要,可以使用const
版本来防止这种情况coll
.
Ste*_*sop 11
6.5.4/1说:
for ( for-range-declaration : braced-init-list ) statement
Run Code Online (Sandbox Code Playgroud)
让range-init等同于braced-init-list.在每种情况下,基于范围的for语句等同于
{
auto && __range = range-init;
for ( auto __begin = begin-expr,
__end = end-expr;
__begin != __end;
++__begin ) {
for-range-declaration = *__begin;
statement
}
}
Run Code Online (Sandbox Code Playgroud)
(进一步解释所有__
gubbins 的含义).
当然,与直接使用而不是使用内部语句相比,该标准不保证该行是否会const auto &e = *__begin
引入性能开销.允许实现通过费力地将指针复制到某个堆栈槽中来实现引用,然后在每次使用引用时将其读回,并且不需要优化.*__begin
e
但是没有理由在合理的编译器中存在开销,在__begin
容器迭代器(operator*
返回引用)的情况下,然后e
通过语句中的值传递.
归档时间: |
|
查看次数: |
3176 次 |
最近记录: |