Saya membuat kelas tipe chaining, seperti contoh kecil di bawah ini. Tampaknya ketika fungsi chaining anggota, maka konstruktor salinan dipanggil. Apakah ada cara untuk menghilangkan panggilan copy constructor? Dalam contoh mainan saya di bawah ini, jelas bahwa saya hanya berurusan dengan hal-hal yang bersifat sementara dan dengan demikian "harus" (mungkin tidak menurut standar, tetapi secara logis) menjadi sebuah keputusan. Pilihan terbaik kedua, untuk menyalin elision, akan menjadi untuk memindahkan konstruktor dipanggil, tetapi ini tidak terjadi.
class test_class {
private:
int i = 5;
public:
test_class(int i) : i(i) {}
test_class(const test_class& t) {
i = t.i;
std::cout << "Copy constructor"<< std::endl;
}
test_class(test_class&& t) {
i = t.i;
std::cout << "Move constructor"<< std::endl;
}
auto& increment(){
i++;
return *this;
}
};
int main()
{
//test_class a{7};
//does not call copy constructor
auto b = test_class{7};
//calls copy constructor
auto b2 = test_class{7}.increment();
return 0;
}
Sunting: Beberapa klarifikasi. 1. Ini tidak tergantung pada level optimisasi. 2. Dalam kode saya yang sebenarnya, saya memiliki objek yang lebih kompleks (misal tumpukan dialokasikan) daripada ints
auto b = test_class{7};
tidak memanggil copy constructor karena itu benar-benar sama dengantest_class b{7};
dan kompiler cukup pintar untuk mengenali kasus ini dan karena itu dapat dengan mudah menghilangkan salinan apa pun. Hal yang sama tidak dapat dilakukan untukb2
.std::cout
) di copy copy Anda? Tanpanya salinan harus dioptimalkan.Jawaban:
Sebagian jawaban (tidak membangun
b2
di tempat, tetapi mengubah konstruksi salinan menjadi konstruksi bergerak): Anda dapat membebaniincrement
fungsi anggota pada kategori nilai instance terkait:Ini menyebabkan
untuk bergerak-membangun
b2
karenatest_class{7}
bersifat sementara, dan&&
kelebihantest_class::increment
disebut.Untuk konstruksi di tempat yang sebenarnya (yaitu bahkan bukan konstruksi pemindahan), Anda dapat mengubah semua fungsi anggota khusus dan non-khusus menjadi
constexpr
versi. Lalu, Anda bisa melakukannyadan Anda tidak bergerak atau menyalin konstruksi untuk membayar. Ini, jelas, mungkin untuk yang sederhana
test_class
, tetapi tidak untuk skenario yang lebih umum yang tidak memungkinkan untukconstexpr
fungsi anggota.sumber
b2
tidak dapat dimodifikasi.constinit
akan menjadi cara untuk pergi ke sana.this
yang sama denganconst
fungsi anggotaPada dasarnya, menetapkan referensi ke suatu nilai membutuhkan pemohon konstruktor, yaitu salinan atau perpindahan . Ini berbeda dari copy-elision di mana diketahui di kedua sisi fungsi sebagai objek berbeda yang sama. Juga referensi dapat merujuk ke objek bersama seperti pointer.
Cara paling sederhana mungkin membuat konstruktor salinan sepenuhnya dioptimalkan. Pengaturan nilai sudah dioptimalkan oleh kompiler, hanya saja
std::cout
yang tidak dapat dioptimalkan.(atau cukup hapus salinan dan pindahkan konstruktor)
contoh hidup
Karena masalah Anda pada dasarnya dengan referensi, solusi mungkin tidak mengembalikan referensi ke objek jika Anda ingin berhenti menyalin dengan cara ini.
Metode ketiga hanya mengandalkan salin salinan di tempat pertama - namun ini membutuhkan penulisan ulang atau enkapsulasi operasi menjadi satu fungsi dan dengan demikian menghindari masalah ini sama sekali (saya sadar ini mungkin bukan yang Anda inginkan, tetapi bisa menjadi solusi untuk pengguna lain):
Metode keempat menggunakan langkah sebagai gantinya, baik dipanggil eksplisit
atau seperti yang terlihat dalam jawaban ini .
sumber