Rvalue referenční Declarator: & &
Obsahuje odkaz na výraz rvalue.
type-id && cast-expression
Poznámky
Rvalue odkazy umožňují odlišit od rvalue lvalue.Lvalue odkazy a rvalue odkazy jsou syntakticky a sémanticky podobné, ale jsou poněkud odlišné pravidlům.Další informace o lvalues a rvalues Lvalues a Rvalues.Další informace o odkazech lvalue viz Odkaz Lvalue Declarator: &.
Následující části popisují, jak rvalue odkazy na podporu provádění přesunout sémantiku a předávání dokonalé.
Přesunout sémantiku
Podporovat provádění odkazy Rvalue přesunout sémantiku, které výrazně zvýšit výkon aplikací.Přesunout sémantiku umožňuje napsat kód, který převádí prostředky (například dynamicky přidělenou paměť) z jednoho objektu na jiný.Přesunete sémantiku funguje, protože umožňuje prostředky mají být převedeny z dočasných objektů, které nelze odkazovat v programu.
Implementace sémantiku přesunout, můžete obvykle poskytují přesunout konstruktoru, a volitelně přesouvání operátor přiřazení (operator=), do třídy.Operace Kopírovat a přiřazení zdrojů, jejichž rvalues jsou pak automaticky využívat přesunout sémantiku.Kompilátor neposkytuje na rozdíl od výchozí konstruktor kopírovat, přesunout výchozí konstruktor.Další informace o zápisu přesunu konstruktor a použít v aplikaci Jak: Zapsat přesun konstruktor.
Také může přetížit běžných funkcí a operátorů využívat přesunout sémantiku.Visual C++ 2010zavádí sémantiku přesunout do standardní šablonu knihovny (STL).Například string třída implementuje operací, které provést přesun sémantiku.Zvažte následující příklad, který spojuje několik řetězců a vytiskne výsledek:
// string_concatenation.cpp
// compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s = string("h") + "e" + "ll" + "o";
cout << s << endl;
}
Před Visual C++ 2010, každé volání operator+ přiděluje a vrátí nové dočasné string objekt (rvalue).operator+nelze připojit jeden řetězec na druhý, protože nejste jisti, zda jsou řetězce zdroje lvalues nebo rvalues.Pokud jsou zdrojové řetězce obou lvalues, může odkazovat v programu a nesmí být proto změněno.Pomocí odkazů na rvalue operator+ můžete upravit tak, aby rvalues, které nelze odkazovat v programu.Proto operator+ jeden řetězec lze nyní přidat do jiného.To může výrazně snížit počet přidělení dynamické paměti, string třídy musí provést.Další informace o string třídy naleznete v tématu basic_string Class.
Sémantika přesunout také pomáhá, když kompilátor nemůže vrátit hodnotu optimalizace (RVO) nebo s názvem vrátit hodnotu optimalizace (NRVO).V těchto případech kompilátor volá konstruktor přesunout, pokud ji definuje typ.Další informace o optimalizaci vrátit hodnotu s názvem s názvem vrátit hodnotu optimalizace v aplikaci Visual C++ 2005.
Pro lepší pochopení sémantiku přesunout, zvažte příklad vložení prvku do vector objektu.Pokud kapacita vector překročení objektu vector musí objekt přidělení paměti pro její prvky a zkopírujte do jiného umístění v paměti místo pro vložený prvek každého prvku.Při operaci vložení kopie prvku, vytvoří nový prvek, volá konstruktor kopírovat kopírování dat z předchozího prvku na nový prvek a potom ničí předchozího prvku.Přesunout sémantiku umožňuje přesunout objekty přímo, bez nutnosti provádět přidělení paměti nákladné a operace kopírování.
Využít sémantiku přesunout v vector například můžete zapsat přesun konstruktor přesunout data z jednoho objektu do jiného.
Další informace o zavedení sémantiku přesunout do STL v Visual C++ 2010, viz Referenční Standardní knihovna C++.
Perfektní předávání
Perfektní předávání snižuje potřebu přetížené funkce a pomáhá zabránit předávání problém.Předávání problém může dojít při zápisu obecnou funkci, která trvá odkazy jako jeho parametry a předá (nebo předává) těchto parametrů pro jinou funkci.Například Obecné funkce přebírá parametr typu const T&, pak volaná funkce nelze upravit hodnotu tohoto parametru.Pokud Obecné funkce přebírá parametr typu T&, pak nelze volat funkci pomocí rvalue (například dočasný objekt nebo Celočíselný literál).
Obvykle tento problém vyřešit, je nutné zadat přetížených verzí funkce obecného, které obě T& a const T& pro každou jeho parametry.V důsledku toho počet přetížené funkce roste exponenciálně počet parametrů.Rvalue odkazy umožňují zapisovat jednu verzi funkci, která přijímá libovolný argumenty a předá jiné funkci, jako by ostatní funkce byl volán přímo.
Zvažte následující příklad, který deklaruje čtyři typy W, X, Y, a Z.Konstruktor pro každý typ má jinou kombinaci const a non-const lvalue odkazy jako jeho parametry.
struct W
{
W(int&, int&) {}
};
struct X
{
X(const int&, int&) {}
};
struct Y
{
Y(int&, const int&) {}
};
struct Z
{
Z(const int&, const int&) {}
};
Předpokládejme, že chcete psát Obecné funkce, která vytváří objekty.Následující příklad ukazuje jeden způsob zápisu této funkce:
template <typename T, typename A1, typename A2>
T* factory(A1& a1, A2& a2)
{
return new T(a1, a2);
}
Následující příklad ukazuje platné volání factory funkce:
int a = 4, b = 5;
W* pw = factory<W>(a, b);
V následujícím příkladu však neobsahuje platný volání factory fungovat, protože factory trvá lvalue odkazy, které lze měnit její parametry, avšak se nazývá pomocí rvalues:
Z* pz = factory<Z>(2, 2);
Obvykle tento problém vyřešit, je nutné vytvořit přetížené verzi factory funkce pro každou kombinaci A& a const A& parametry.Rvalue odkazy umožňují zapisovat jednu verzi factory funkci, jak je znázorněno v následujícím příkladu:
template <typename T, typename A1, typename A2>
T* factory(A1&& a1, A2&& a2)
{
return new T(std::forward<A1>(a1), std::forward<A2>(a2));
}
Tento příklad používá jako parametry, rvalue odkazy factory funkce.Účelem std::forward funkcí je předat parametry výroby funkce konstruktoru třídy šablony.
Následující příklad ukazuje main funkce, která používá opraveného factory funkce vytváření instancí W, X, Y, a Z třídy.Opraveného factory funkce konstruktoru třídy odpovídající předá jeho parametry (lvalues nebo rvalues).
int main()
{
int a = 4, b = 5;
W* pw = factory<W>(a, b);
X* px = factory<X>(2, b);
Y* py = factory<Y>(a, 2);
Z* pz = factory<Z>(2, 2);
delete pw;
delete px;
delete py;
delete pz;
}
Další vlastnosti Rvalue odkazy
Funkce lvalue odkazu a odkaz rvalue může přetížit.
Pomocí funkce přijmout přetížení const lvalue odkaz nebo odkaz na rvalue můžete napsat kód, který rozlišuje mezi-jako upravitelné objekty (lvalues) a upravitelné dočasné hodnoty (rvalues).Objekt můžete předat funkci, která trvá odkazu na rvalue, pokud je objekt označen jako const.Následující příklad ukazuje funkci f, což je přetížena lvalue odkazu a odkaz rvalue.main Volání funkce f s lvalues a rvalue.
// reference-overload.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};
void f(const MemoryBlock&)
{
cout << "In f(const MemoryBlock&). This version cannot modify the parameter." << endl;
}
void f(MemoryBlock&&)
{
cout << "In f(MemoryBlock&&). This version can modify the parameter." << endl;
}
int main()
{
MemoryBlock block;
f(block);
f(MemoryBlock());
}
Tento příklad vytvoří následující výstup:
In f(const MemoryBlock&). This version cannot modify the parameter.
In f(MemoryBlock&&). This version can modify the parameter.
Například první volání f předává místní proměnné (lvalue) jako svůj argument.Druhé volání f předává dočasný objekt jako svůj argument.Protože dočasný objekt se nelze odkazovat v programu, vytvoří vazbu volání přetížené verzi f , která má rvalue odkaz, který je bez objekt upravit.
Kompilátor zpracovává odkaz s názvem rvalue jako lvalue a odkazu na nepojmenované rvalue jako rvalue.
Při psaní funkce, která se bere jako svůj parametr odkaz rvalue parametru se zachází jako lvalue v těle funkce.Odkaz s názvem rvalue kompilátor zachází jako lvalue, protože pojmenovaný objekt lze označit několik částí programu; bylo by nebezpečné povolit více částí program změnit nebo odebrat z tohoto objektu zdroje.Například pokud více částí programu převést prostředky ze stejného objektu, první část bude úspěšně přenést zdroje.
Následující příklad ukazuje funkci g, což je přetížena lvalue odkazu a odkaz rvalue.Funkce f rvalue odkaz bere jako svůj parametr (odkaz s názvem rvalue) a vrátí odkaz rvalue (nepojmenované rvalue odkaz).Ve volání g z f, řešení přetížení vybere verzi g , protože přebírá odkaz lvalue těla f jeho parametr zachází jako lvalue.Ve volání g z main, řešení přetížení vybere verzi g , protože trvá odkazu na rvalue f rvalue odkaz vrátí.
// named-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};
void g(const MemoryBlock&)
{
cout << "In g(const MemoryBlock&)." << endl;
}
void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}
MemoryBlock&& f(MemoryBlock&& block)
{
g(block);
return block;
}
int main()
{
g(f(MemoryBlock()));
}
Tento příklad vytvoří následující výstup:
In g(const MemoryBlock&).
In g(MemoryBlock&&).
V tomto příkladu main funkce předává rvalue na f.Text f jeho pojmenovaný parametr zachází jako lvalue.Volání z f na g parametr váže na odkaz lvalue (první verze přetížené g).
- Můžete obsadit lvalue na odkaz rvalue.
STL std::move funkce umožňuje převést objekt na rvalue odkaz na tento objekt.Můžete také použít static_cast klíčové odevzdaných lvalue na odkaz, rvalue, jak je znázorněno v následujícím příkladu:
// cast-reference.cpp
// Compile with: /EHsc
#include <iostream>
using namespace std;
// A class that contains a memory resource.
class MemoryBlock
{
// TODO: Add resources for the class here.
};
void g(const MemoryBlock&)
{
cout << "In g(const MemoryBlock&)." << endl;
}
void g(MemoryBlock&&)
{
cout << "In g(MemoryBlock&&)." << endl;
}
int main()
{
MemoryBlock block;
g(block);
g(static_cast<MemoryBlock&&>(block));
}
Tento příklad vytvoří následující výstup:
In g(const MemoryBlock&).
In g(MemoryBlock&&).
Funkce šablony odvodit jejich argument typy šablon a potom pomocí referenční sbalení pravidla.
Je běžné zapsat šablonu funkce, která prochází (nebo předává) jeho parametry pro jinou funkci.Je důležité pochopit Princip šablony typu srážky pro funkce šablony, které rvalue odkazy.
Pokud je argumentem funkce rvalue, kompilátor deduces argument je odkaz rvalue.Například předat odkaz na objekt typu rvalue X funkce šablony, která trvá typu T&& jako svůj parametr šablony argument odpočet deduces T se X.Proto je parametr typu X&&.Pokud je argument funkce lvalue nebo const lvalue, kompilátor deduces jeho typ odkazu lvalue nebo const lvalue odkaz tohoto typu.
Následující příklad deklaruje jednu šablonu struktury a poté specializuje pro různé typy odkazů.print_type_and_value Funkce bere jako svůj parametr odkazu rvalue a předá jej odpovídající verze specializované S::print metoda.main Funkce znázorňuje různé způsoby volání S::print metoda.
// template-type-deduction.cpp
// Compile with: /EHsc
#include <iostream>
#include <string>
using namespace std;
template<typename T> struct S;
// The following structures specialize S by
// lvalue reference (T&), const lvalue reference (const T&),
// rvalue reference (T&&), and const rvalue reference (const T&&).
// Each structure provides a print method that prints the type of
// the structure and its parameter.
template<typename T> struct S<T&> {
static void print(T& t)
{
cout << "print<T&>: " << t << endl;
}
};
template<typename T> struct S<const T&> {
static void print(const T& t)
{
cout << "print<const T&>: " << t << endl;
}
};
template<typename T> struct S<T&&> {
static void print(T&& t)
{
cout << "print<T&&>: " << t << endl;
}
};
template<typename T> struct S<const T&&> {
static void print(const T&& t)
{
cout << "print<const T&&>: " << t << endl;
}
};
// This function forwards its parameter to a specialized
// version of the S type.
template <typename T> void print_type_and_value(T&& t)
{
S<T&&>::print(std::forward<T>(t));
}
// This function returns the constant string "fourth".
const string fourth() { return string("fourth"); }
int main()
{
// The following call resolves to:
// print_type_and_value<string&>(string& && t)
// Which collapses to:
// print_type_and_value<string&>(string& t)
string s1("first");
print_type_and_value(s1);
// The following call resolves to:
// print_type_and_value<const string&>(const string& && t)
// Which collapses to:
// print_type_and_value<const string&>(const string& t)
const string s2("second");
print_type_and_value(s2);
// The following call resolves to:
// print_type_and_value<string&&>(string&& t)
print_type_and_value(string("third"));
// The following call resolves to:
// print_type_and_value<const string&&>(const string&& t)
print_type_and_value(fourth());
}
Tento příklad vytvoří následující výstup:
print<T&>: first
print<const T&>: second
print<T&&>: third
print<const T&&>: fourth
Řešení každé volání print_type_and_value funkce kompilátoru provede nejprve šablonu argument srážek.Kompilátor pak platí odkaz sbalení pravidla, když ji nahradí argumenty deduced šablony pro typy parametrů.Například předávání místní proměnné s1 na print_type_and_value funkce způsobuje kompilátor vyrábět podpis následující funkce:
print_type_and_value<string&>(string& && t)
Kompilátor používá ke zmenšení podpis následující odkaz sbalení pravidla:
print_type_and_value<string&>(string& t)
Tato verze print_type_and_value funkci předá jeho parametr správná verze specializované S::print metoda.
Následující tabulka shrnuje referenční sbalení pravidla pro šablonu argument typ srážky:
Rozšířený typ |
Tento typ |
T& & |
T& |
T& && |
T& |
T&& & |
T& |
T&& && |
T&& |
Šablony argument je důležitým prvkem provádění perfektní předávání.Část perfektní předávání, které se předkládá v tomto tématu, popisuje předávání dokonalé podrobněji.
SHRNUTÍ
Rvalue odkazy odlišit od rvalues lvalues.Mohou pomoci zvýšit výkon aplikací zapojují přidělení paměti zbytečné a operace kopírování.Umožňují také zapsat jednu verzi funkci, která přijímá libovolný argumenty a předá jiné funkci, jako by ostatní funkce byl volán přímo.
Viz také
Úkoly
Jak: Zapsat přesun konstruktor