Po pierwsze, kilka ogólnych porad dotyczących korzystania z auto
, które nie są specyficzne dla zakresu. auto&&
może być problematyczne, jeśli inicjalizator jest wartością xvalue odnoszącą się do tymczasowego, ponieważ nie można zastosować w tym przypadku przedłużenia okresu istnienia. Mówiąc prościej, a z kodem:
// 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 {});
Dużą wskazówką, że coś jest zacieniony tutaj dzieje jest to, że id
ma typ T&&
powrócić. Gdyby zwrócono T
, wówczas id(whatever)
byłaby wartością pryncypium, a zwrócony tymczasowy okres eksploatacji zostałby przedłużony do końca życia (jednak wymagałoby to budowy).
Z iż z drogi, jeśli chodzi o zasięg, bo choć trzeba pamiętać, że for(auto&& ref: init) { /* body */ }
określony jest w przybliżeniu równowartość (pomijając pewne szczegóły, które nie mają znaczenia tutaj):
{
using std::begin;
using std::end;
auto&& range = init;
for(auto b = begin(range), e = end(range); b != e; ++b) {
auto&& ref = *b;
/* body */
}
}
Musimy zadać sobie teraz, co zrobić, jeśli *b
jest xvalue (czyli typ iterator posiada operator*
powrocie value_type&&
, jak to ma miejsce np std::move_iterator<Iterator>
)? Musi on następnie odwoływać się do obiektu, który będzie odbiegał od linii auto&& ref = *b;
. Dlatego jest bezpieczny. W przeciwnym razie, jeśli *b
jest wartością pritalną (to znaczy typ iteratora ma wartość operator*
, zwracając T
dla pewnego typu obiektu T
), wówczas czas życia tymczasowego zostaje przedłużony na resztę korpusu pętli. We wszystkich przypadkach jesteś bezpieczny (przypadek, w którym *b
jest lwartością, która została pozostawiona ćwiczeniu dla czytelnika).
Osobiście intensywnie korzystam z auto&&
z lub bez zasięgu. Ale za każdym razem zadaję sobie pytanie, czy inicjalizator jest wartością x, czy nie, a jeśli tak, to jaki jest czas trwania tego, o czym się mówi.
Dla biednych użytkowników MSVC10, którzy nie mogą czerpać korzyści z zakresu, to samo pytanie dotyczy 'BOOST_FOREACH'. –
'auto' nigdy nie jest' const'. Musisz powiedzieć "auto const &". Również 'auto &&' nie jest referencją rvalue, ale raczej "odwołaniem uniwersalnym". –
@KerrekSB Dobra informacja, że 'const' nie jest tam wyprowadzona. Nigdy nie powiedziałem nic o referencjach rvalue, v) – Potatoswatter