C++ 基于范围的声明的正确样式
提到了基于范围的C++11的明显的惯用用法C++ 基于范围的声明的正确样式,c++,for-loop,c++11,perfect-forwarding,C++,For Loop,C++11,Perfect Forwarding,提到了基于范围的C++11的明显的惯用用法 for (auto& elem: container) { // do something with elem } 不过,我一直怀疑你应该使用哪种参考资料。输入迭代器可能返回右值。虽然可以将auto引入的隐式类型推断为绑定到右值的const,但似乎没有发生这种情况 使用完美转发是否是最佳的常规做法 for (auto && elem: container) { // do something with elem }
for (auto& elem: container) {
// do something with elem
}
不过,我一直怀疑你应该使用哪种参考资料。输入迭代器可能返回右值。虽然可以将auto
引入的隐式类型推断为绑定到右值的const
,但似乎没有发生这种情况
使用完美转发是否是最佳的常规做法
for (auto && elem: container) {
// do something with elem
}
我看不出有什么坏处,但它看起来有点太可爱了。也许我还没有写足够的C++11。首先,关于如何使用
auto
的一些一般性建议,这些建议并不是特定于的范围<如果初始值设定项是引用临时值的xvalue,则code>auto&可能会有问题,因为在这种情况下可能不会应用生存期扩展。更简单地说,使用代码:
// Pass-through identity function that doesn't construct objects
template<typename T>
T&&
id(T&& t)
{ return std::forward<T>(t); }
// Ok, lifetime extended
// T {} is a prvalue
auto&& i = T {};
T* address = &i;
// Still ok: lifetime of the object referred to by i exceed that of j
// id(whatever) is an xvalue
auto&& j = id(std::move(i));
// No other object is involved or were constructed,
// all those references are bound to the same object
assert( &j == address );
// Oops, temporary expires at semi-colon
// id(whatever) is an xvalue, again
auto&& k = id(T {});
我们现在需要问问自己,如果*b
是一个xvalue(即迭代器类型有一个操作符*
返回值类型&&
,例如使用std::move_迭代器&
)该怎么办?然后它必须引用一个比ref
更长寿的对象,因为行auto&&ref=*b代码>不涉及临时的。因此它是安全的。否则,如果*b
是一个PR值(即迭代器类型有一个操作符*
返回T
,用于某些对象类型T
),则临时对象的生存期将延长到循环体的其余部分。在所有情况下,您都是安全的(在这种情况下,*b
是一个左值,留给读者作为练习)
我个人大量使用自动和&
,有或没有范围。但每次我都会问自己,初始值设定项是否是xvalue,如果是,所指内容的生命周期是什么。对于那些不能享受基于范围的For的可怜的MSVC10用户,同样的问题也适用于BOOST\u FOREACH
自动从不const
。你需要说自动常量&
。另外,auto&&
不是一个右值参考,而是一个“通用参考”。@KerrekSB这是一个很好的信息,const
。我从来没有说过关于右值引用的任何事情;v) 我应该补充一点,我并不是真的指“永远”:当然constinta=1;自动&ra=a代码>按预期工作。但是auto
永远不会变得比它需要的更稳定。@KerrekSB你能澄清一下吗const
是在函数参数上下文中推导出来的,而auto
就是根据它定义的,没有例外。这似乎很好:int const i=5;自动&x=i代码>编辑哈哈,好的:v)。好吧,在任何情况下,它都不会猜测左值引用应该被设置为const以绑定到右值。很好的信息。另一个透视图…函数可以返回xvalue的唯一临时变量是右值参数begin
和end
不接受任何参数,因此转发它们的结果是安全的。@PotatosWater在本例中,感兴趣的是*b
(实际上不接受参数,更不用说您正确分析的临时参数)begin
和end
确实接受参数,但它们只适用于左值。是的,我指的是begin
和end
成员,并且排除此
,因为它是左值operator*
接受的参数与begin
和end
的含义基本相同。但这才是最重要的。
{
using std::begin;
using std::end;
auto&& range = init;
for(auto b = begin(range), e = end(range); b != e; ++b) {
auto&& ref = *b;
/* body */
}
}