Во-первых, несколько общих советов о том, как использовать auto
, которые не относятся к диапазону. auto&&
может быть проблематично, если инициализатором является значение x, относящееся к временному, поскольку в этом случае продление срока службы может не применяться. Проще говоря, и с кодом:
// 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 (то есть тип итератора имеет operator*
, возвращающий T
для некоторого типа объекта T
), тогда время жизни временного объекта увеличивается для остальной части тела цикла. Во всех случаях вы в безопасности (случай, когда *b
- это lvalue, оставляемое читателю в качестве упражнения).
Лично я интенсивно использую auto&&
, с диапазоном или без него. Но я спрашиваю себя каждый раз, является ли инициализатор значением x или нет, и если да, то каково время жизни того, на что ссылаются.