Penghapusan salinan diizinkan terjadi dalam sejumlah keadaan. Namun, bahkan jika diizinkan, kode tersebut masih harus dapat berfungsi seolah-olah salinannya tidak dihilangkan. Yaitu, harus ada salinan yang dapat diakses dan / atau konstruktor pindahkan.
Penghapusan salinan yang dijamin mengubah sejumlah konsep C ++, sehingga keadaan tertentu di mana salinan / pemindahan dapat dihilangkan tidak benar-benar memicu penyalinan / pemindahan sama sekali . Kompilator tidak meminta salinan; standar mengatakan bahwa penyalinan seperti itu tidak akan pernah terjadi.
Pertimbangkan fungsi ini:
T Func() {return T();}
Di bawah aturan penghapusan salinan tanpa jaminan, ini akan membuat sementara, lalu pindah dari sementara itu ke nilai kembalian fungsi. Operasi pemindahan tersebut dapat dieliminasi, tetapi T
masih harus memiliki konstruktor pemindahan yang dapat diakses meskipun tidak pernah digunakan.
Demikian pula:
T t = Func();
Ini adalah salinan inisialisasi t
. Ini akan menyalin menginisialisasi t
dengan nilai kembalian Func
. Namun, T
tetap harus memiliki konstruktor bergerak, meskipun tidak akan dipanggil.
Penghapusan salinan yang dijamin mengubah arti dari ekspresi prvalue . Sebelum C ++ 17, prvalues adalah objek sementara. Dalam C ++ 17, ekspresi prvalue hanyalah sesuatu yang dapat terwujud sementara, tetapi belum bersifat sementara.
Jika Anda menggunakan prvalue untuk menginisialisasi objek dari tipe prvalue, maka tidak ada sementara yang terwujud. Saat Anda melakukannya return T();
, ini menginisialisasi nilai kembalian fungsi melalui nilai pr. Sejak fungsi itu kembali T
, tidak ada sementara yang dibuat; inisialisasi nilai pr hanya secara langsung menilai nilai kembali.
Hal yang perlu dipahami adalah, karena nilai yang dikembalikan adalah nilai pr, maka itu belum menjadi objek . Ini hanyalah sebuah penginisialisasi untuk sebuah objek, seperti T()
adanya.
Ketika Anda melakukannya T t = Func();
, prvalue dari nilai yang dikembalikan langsung menginisialisasi objek t
; tidak ada tahap "buat sementara dan salin / pindahkan". Karena Func()
nilai yang dikembalikan adalah prvalue yang setara dengan T()
, t
langsung diinisialisasi oleh T()
, persis seperti yang Anda lakukan T t = T()
.
Jika prvalue digunakan dengan cara lain, prvalue akan menjadi objek sementara, yang akan digunakan dalam ekspresi itu (atau dibuang jika tidak ada ekspresi). Jadi jika Anda melakukannya const T &rt = Func();
, prvalue akan terwujud sementara (menggunakan T()
sebagai penginisialisasi), yang referensinya akan disimpan rt
, bersama dengan hal ekstensi seumur hidup sementara yang biasa.
Satu hal yang dijamin elision mengizinkan Anda lakukan adalah mengembalikan objek yang tidak bergerak. Misalnya, lock_guard
tidak bisa disalin atau dipindahkan, jadi Anda tidak bisa memiliki fungsi yang mengembalikannya dengan nilai. Tetapi dengan jaminan penghapusan salinan, Anda bisa.
Elision terjamin juga bekerja dengan inisialisasi langsung:
new T(FactoryFunction());
Jika FactoryFunction
dikembalikan T
dengan nilai, ekspresi ini tidak akan menyalin nilai kembali ke memori yang dialokasikan. Ini akan mengalokasikan memori dan menggunakan memori yang dialokasikan sebagai memori nilai kembali untuk pemanggilan fungsi secara langsung.
Jadi fungsi pabrik yang mengembalikan berdasarkan nilai bisa langsung menginisialisasi memori yang dialokasikan heap tanpa menyadarinya. Selama fungsi ini secara internal mengikuti aturan jaminan penghapusan salinan, tentunya. Mereka harus mengembalikan nilai prnilai tipe T
.
Tentu saja, ini juga berfungsi:
new auto(FactoryFunction());
Jika Anda tidak suka menulis nama jenis.
Penting untuk diketahui bahwa jaminan di atas hanya berlaku untuk prvalues. Artinya, Anda tidak mendapatkan jaminan saat mengembalikan variabel bernama :
T Func()
{
T t = ...;
...
return t;
}
Dalam hal ini, t
harus masih memiliki konstruktor copy / move yang dapat diakses. Ya, kompilator dapat memilih untuk mengoptimalkan penyalinan / pemindahan. Tetapi compiler masih harus memverifikasi keberadaan konstruktor copy / move yang dapat diakses.
Jadi tidak ada perubahan untuk pengoptimalan nilai pengembalian bernama (NRVO).
std::function<T()>
.