Pot*_*ter 12 c++ for-loop perfect-forwarding c++11
这个问题提到了C++ 11基于范围的显而易见的惯用法.
for (auto& elem: container) {
// do something with elem
}
Run Code Online (Sandbox Code Playgroud)
不过,我一直怀疑你应该使用哪种参考.输入迭代器可以返回rvalues.尽管auto
可以推导出引入的隐式类型const
将绑定到右值,但这似乎不会发生.
使用完美转发是最好的通用做法吗?
for (auto && elem: container) {
// do something with elem
}
Run Code Online (Sandbox Code Playgroud)
我觉得这里没有缺点,但看起来有点太可爱了.也许我还没有写好C++ 11.
首先,关于如何使用auto
它的一些一般性建议并非特定于范围.auto&&
如果初始化程序是指向临时的xvalue,则可能会出现问题,因为在这种情况下可能不会应用生存期扩展.更简单地说,并使用代码:
// 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 {});
Run Code Online (Sandbox Code Playgroud)
这里有一些阴暗的重要线索是id
返回类型T&&
.如果它返回T
那么id(whatever)
将是一个prvalue,并且返回的临时将延长其寿命(但是这将涉及构造).
除此之外,当涉及到范围时 - 虽然你必须记住,for(auto&& ref: init) { /* body */ }
指定大致相当于以下(忽略一些无关紧要的细节):
{
using std::begin;
using std::end;
auto&& range = init;
for(auto b = begin(range), e = end(range); b != e; ++b) {
auto&& ref = *b;
/* body */
}
}
Run Code Online (Sandbox Code Playgroud)
我们现在需要问自己,如果*b
是xvalue(即迭代器类型有operator*
返回的话value_type&&
,如同的情况那样std::move_iterator<Iterator>
)?然后,它必须指向一个对象,会活得比ref
,因为线路auto&& ref = *b;
不涉及暂时的.因此它是安全的.否则,如果*b
是prvalue(即迭代器类型具有某些对象类型的operator*
返回),则临时体的生命周期将延伸到循环体的其余部分.在所有情况下,你都是安全的(左手是左手作为练习留给读者的情况).T
T
*b
我个人大量使用auto&&
,有或没有范围.但是我每次都会问自己,初始化程序是否是xvalue,如果是,是什么,被引用的是什么.