Zunächst einige allgemeine Hinweise zur Verwendung von , die nicht spezifisch für den Bereich ist. auto&&
kann problematisch sein, wenn der Initialisierer ein xvalue ist, der sich auf einen temporären Wert bezieht, da in diesem Fall die lebenslange Erweiterung nicht angewendet werden kann. Um es einfach auszudrücken, und mit dem Code:
// 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 {});
Die große Ahnung, dass es etwas schattig ist hier los ist, dass id
zurückkehren muss Typen T&&
. Wenn es T
zurückgibt, dann wäre id(whatever)
ein prvalue, und das zurückgekehrte temporäre hätte seine Lebensdauer verlängert (aber das würde eine Konstruktion beinhalten).
Mit diesem aus dem Weg, wenn es darum geht zu für reichen, obwohl Sie müssen bedenken, dass for(auto&& ref: init) { /* body */ }
zu etwa gleichwertig sein angegeben wird die folgenden (einige Details zu ignorieren, die nicht Sache hier zu tun):
{
using std::begin;
using std::end;
auto&& range = init;
for(auto b = begin(range), e = end(range); b != e; ++b) {
auto&& ref = *b;
/* body */
}
}
Wir müssen uns jetzt fragen, was passiert, wenn *b
ein xValue (dh der Iteratortyp hat ein operator*
value_type&&
Rückkehr, wie es der Fall mit std::move_iterator<Iterator>
zB ist)? Es muss sich dann auf ein Objekt beziehen, dass ref
überlebt, da die Zeile auto&& ref = *b;
keine temporäre enthält. Daher ist es sicher. Andernfalls, wenn *b
ein prvalue ist (d. H. Der Iteratortyp hat einen operator*
, der T
für einen Objekttyp T
zurückgibt), wird die Lebensdauer des temporären Objekts für den Rest des Schleifenkörpers erweitert. In allen Fällen sind Sie sicher (der Fall, in dem *b
ein Wert ist, der dem Leser als Übung überlassen wird).
Ich persönlich verwende stark auto&&
, mit oder ohne Reichweite-für. Aber ich frage mich jedes Mal, ob der Initialisierer ein xvalue ist oder nicht, und wenn ja, was ist die Lebenszeit von dem, worauf Bezug genommen wird.
Für die armen MSVC10-Benutzer, die Reichweite nicht genießen können, gilt die gleiche Frage für 'BOOST_FOREACH'. –
'auto' ist nie' const'. Sie müssen 'auto const &' sagen. Außerdem ist 'auto &&' keine rvalue-Referenz, sondern eher eine "universelle Referenz". –
@KerrekSB Gute Info, dass 'const' dort nicht abgeleitet ist. Ich habe nie etwas über rvalue-Referenzen gesagt; v) – Potatoswatter