首先,一些關於如何使用auto
的一般性建議,它不是特定於range-for的。 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 {});
大線索,有一些陰暗的事情在這裏是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 */
}
}
我們要問自己,現在,如果*b
是x值(即迭代器類型有一個operator*
返回value_type&&
,如同例如用std::move_iterator<Iterator>
的情況下)?因此,它必須參考將長出ref
的對象,因爲行auto&& ref = *b;
不涉及臨時。因此它是安全的。否則,如果*b
是一個prvalue(即對於某些對象類型T
,迭代器類型具有operator*
返回T
),則臨時的生命週期將在循環體的其餘部分進行擴展。在所有情況下,你都是安全的(*b
是一個左值作爲練習讀者的情況)。
我個人大量使用auto&&
,有或沒有range-for。但是我每次都會問自己,初始化器是否是一個xvalue,如果是,那麼被引用的是什麼時間。
對於無法享受基於範圍的窮人MSVC10用戶,相同的問題適用於'BOOST_FOREACH'。 – 2012-04-03 13:59:49
'auto'永遠不是'const'。你需要說'auto const&'。另外,'auto &&'不是右值引用,而更像是「通用引用」。 – 2012-04-03 14:56:45
@KerrekSB在這裏沒有推導出'const'的好消息。我從來沒有說任何有關右值引用; v) – Potatoswatter 2012-04-03 15:03:22