Jawaban sederhananya adalah Anda harus menulis kode untuk referensi nilai seperti halnya Anda menggunakan kode referensi reguler, dan Anda harus memperlakukan mereka dengan 99% mental yang sama. Ini termasuk semua aturan lama tentang pengembalian referensi (yaitu tidak pernah mengembalikan referensi ke variabel lokal).
Kecuali Anda menulis kelas templat templat yang perlu mengambil keuntungan dari std :: forward dan dapat menulis fungsi generik yang mengambil referensi baik nilai atau nilai, ini lebih atau kurang benar.
Salah satu keuntungan besar untuk memindahkan konstruktor dan memindahkan tugas adalah bahwa jika Anda mendefinisikannya, kompilator dapat menggunakannya dalam kasus-kasus adalah RVO (optimasi nilai kembali) dan NRVO (bernama optimasi nilai pengembalian) gagal dipanggil. Ini cukup besar untuk mengembalikan benda mahal seperti wadah & string dengan nilai secara efisien dari metode.
Sekarang hal-hal yang menarik dengan referensi nilai, adalah Anda juga dapat menggunakannya sebagai argumen untuk fungsi normal. Ini memungkinkan Anda untuk menulis kontainer yang memiliki kelebihan muatan untuk referensi const (const foo & lainnya) dan nilai referensi (foo && lainnya). Sekalipun argumen terlalu berat untuk dilewatkan dengan panggilan konstruktor belaka, masih bisa dilakukan:
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));
}
Wadah STL telah diperbarui untuk memindahkan kelebihan muatan untuk hampir semua hal (kunci hash dan nilai, penyisipan vektor, dll), dan di sinilah Anda paling sering melihatnya.
Anda juga dapat menggunakannya untuk fungsi normal, dan jika Anda hanya memberikan argumen referensi nilai, Anda dapat memaksa pemanggil untuk membuat objek dan membiarkan fungsi melakukan gerakan. Ini lebih merupakan contoh daripada penggunaan yang benar-benar baik, tetapi di perpustakaan rendering saya, saya telah menetapkan string ke semua sumber daya yang dimuat, sehingga lebih mudah untuk melihat apa yang diwakili setiap objek dalam debugger. Tampilannya kira-kira seperti ini:
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;
}
Ini adalah bentuk 'abstraksi bocor' tetapi memungkinkan saya untuk mengambil keuntungan dari fakta bahwa saya harus membuat string sudah sebagian besar waktu, dan menghindari membuat salinan lain dari itu. Ini bukan kode berkinerja tinggi tetapi merupakan contoh yang baik tentang kemungkinan orang memahami fitur ini. Kode ini sebenarnya mengharuskan variabel menjadi sementara untuk panggilan, atau std :: move dipanggil:
// move from temporary
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, string("Checkerboard"));
atau
// 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));
atau
// 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));
tetapi ini tidak akan dikompilasi!
string str("Checkerboard");
TextureHandle htex = CreateTexture(128, 128, A8R8G8B8, str);