Bunun basit cevabı, normal referans kodu gibi rvalue referansları için kod yazmanız ve onlara zihinsel olarak% 99 oranında davranmanızdır. Bu, başvuruları döndürmeyle ilgili tüm eski kuralları içerir (yani hiçbir zaman yerel değişkene başvuru döndürmez).
Std :: forward avantajından faydalanmak ve lvalue veya rvalue referanslarını alan genel bir işlev yazmak için bir template container sınıfı yazmıyorsanız, bu aşağı yukarı doğrudur.
Taşıma yapıcısının ve taşıma atamasının en büyük avantajlarından biri, bunları tanımlarsanız, derleyicinin RVO (dönüş değeri optimizasyonu) ve NRVO (adı verilen dönüş değeri optimizasyonu) çağrılamadığı durumlarda bunları kullanabilmesidir. Bu, kapsayıcılar ve dizeler gibi pahalı nesneleri yöntemlerden verimli bir şekilde değerle döndürmek için oldukça büyüktür.
Şimdi, değer referansları ile işlerin ilginçleştiği yer, bunları normal işlevlere argüman olarak da kullanabilmenizdir. Bu, hem const referansı (const foo & diğer) hem de rvalue referansı (foo && other) için aşırı yükleri olan kaplar yazmanıza olanak tanır. Argüman sadece bir yapıcı çağrısı ile geçilemeyecek kadar bile olsa yine de yapılabilir:
std::vector vec;
for(int x=0; x<10; ++x)
{
// automatically uses rvalue reference constructor if available
// because MyCheapType is an unamed temporary variable
vec.push_back(MyCheapType(0.f));
}
std::vector vec;
for(int x=0; x<10; ++x)
{
MyExpensiveType temp(1.0, 3.0);
temp.initSomeOtherFields(malloc(5000));
// old way, passed via const reference, expensive copy
vec.push_back(temp);
// new way, passed via rvalue reference, cheap move
// just don't use temp again, not difficult in a loop like this though . . .
vec.push_back(std::move(temp));
}
STL kapları, neredeyse her şey (karma anahtarı ve değerleri, vektör ekleme, vb.) İçin aşırı yük taşıyacak şekilde güncellendi ve bunları en çok göreceğiniz yer.
Bunları normal işlevler için de kullanabilirsiniz ve yalnızca bir değer referansı bağımsız değişkeni sağlarsanız, arayanı nesneyi oluşturmaya zorlayabilir ve işlevin hareketi yapmasına izin verebilirsiniz. Bu gerçekten iyi bir kullanımdan daha fazla bir örnektir, ancak oluşturma kütüphanemde, yüklenen tüm kaynaklara bir dize atadım, böylece her nesnenin hata ayıklayıcıda neyi temsil ettiğini görmek daha kolay. Arayüz böyle bir şeydir:
TextureHandle CreateTexture(int width, int height, ETextureFormat fmt, string&& friendlyName)
{
std::unique_ptr<TextureObject> tex = D3DCreateTexture(width, height, fmt);
tex->friendlyName = std::move(friendlyName);
return tex;
}
Bu bir 'sızdıran soyutlama' biçimidir, ancak çoğu zaman dizeyi oluşturmak zorunda olduğum gerçeğinden yararlanmamı ve bunun başka bir kopyasını yapmaktan kaçınmamı sağlar. Bu tam olarak yüksek performanslı bir kod değildir, ancak insanlar bu özelliğin tadını çıkarırken olasılıklara iyi bir örnektir. Bu kod aslında değişkenin çağrı için geçici olmasını veya std :: move invoked olmasını gerektirir:
// move from temporary
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string("Checkerboard"));
veya
// explicit move (not going to use the variable 'str' after the create call)
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, std::move(str));
veya
// explicitly make a copy and pass the temporary of the copy down
// since we need to use str again for some reason
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string(str));
ama bu derlenmeyecek!
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, str);