Referensi cepat kategori nilai C ++: Bagian 1

gambar

Tujuan dari referensi cepat ini adalah untuk mengumpulkan di satu tempat dan mengatur informasi tentang kategori nilai dalam C ++, penugasan, melewati parameter dan kembali dari fungsi. Saya mencoba membuat referensi cepat ini mudah untuk membandingkan dengan cepat dan memilih salah satu solusi yang mungkin, inilah mengapa saya membuat beberapa tabel di sini.


Untuk pengantar topik, silakan gunakan tautan berikut:


C ++ nilai referensi dan pindahkan semantik untuk pemula
Nilai ditentukan ulang
C ++ bergerak untuk orang-orang yang tidak tahu atau peduli dengan nilai apa
Scott Meyers. C ++ Modern yang Efektif. 2015
Memahami Pindah Semantik dan Penerusan Sempurna: Bagian 1
Memahami Pindah Semantik dan Penerusan Sempurna: Bagian 2
Memahami Pindah Semantik dan Penerusan Sempurna: Bagian 3
Apakah kita perlu memindahkan dan menyalin tugas


Kategori nilai


gambar


Dimulai dengan C ++ 11, ekspresi apa pun hanya dapat dimiliki oleh salah satu dari tiga kategori nilai: lvalue, xvalue, atau prvalue:


  • xvalue (nilai kedaluwarsa) - ekspresi, yang mengidentifikasi objek non-sementara, yang dapat dipindahkan
  • lvalue (nilai kiri) - ekspresi, yang mengidentifikasi objek non-temporer dari fungsi, yang tidak dapat dipindahkan
  • prvalue (rvalue murni) - ekspresi, yang menginisialisasi objek

gambar


Tiga kategori ini dapat dikelompokkan menjadi tiga kelompok yang tumpang tindih:


  • glvalue (lvalue umum) mengelompokkan nilai dan x nilai. glvalue memiliki alamat di memori (memiliki identitas) dan dengan demikian biasanya dapat diberi nilai (jika bukan const)
  • kelompok nilai prvalue dan xvalue. rvalue dapat dipindahkan (xvalue) atau tidak termasuk objek yang sama sekali (prvalue). nilai dapat dilewatkan untuk memindahkan konstruktor, memindahkan operator penugasan atau memindahkan fungsi

Jadi, xvalue memiliki alamat di memori dan dapat dipindahkan.


gambar


Anda dapat melihat dari tabel di atas, bahwa variabel bernama lvalue, lvalue reference dan rvalue reference categoroties semuanya memiliki kategori ekspresi yang sama: lvalue (disorot dengan merah). Sebagai contoh, ini berarti, bahwa ketika referensi nilai diteruskan ke suatu fungsi, kelebihan referensi referensi nilai akan dipilih: T&& x=T(); f(x); T&& x=T(); f(x);


Tautan:
C ++ lvalue rvalue xvalue prvalue
Kategori nilai dalam C ++ 17
Kategori nilai


Singkatan dalam artikel ini


Singkatan dari konstruktor, operator, dan destruktor:


  • Dc - Konstruktor default
  • Pc - Konstruktor berparameter
  • Cc - Salin konstruktor
  • Ca - Salin tugas (dapat menggunakan kembali penyimpanan yang dialokasikan, misalnya untuk std :: string)
  • Mc - Pindahkan konstruktor
  • Ma - Pindahkan tugas
  • Va - operator penugasan konversi
  • D - Destructor

Singkatan dari kategori nilai:


  • LV - Lvalue: T LV;
  • LR - Referensi nilai: T& LR = LV;
  • XV - Xvalue: move(LV)
  • PRV - Nilai murni. Literal atau hasil pemanggilan fungsi, yang tipe pengembaliannya bukan referensi: T f() { return T(); } T f() { return T(); }
  • FR - Referensi penerusan: auto&& FR = LV;
  • CLV - const LV. CLR - const LR. CXV - const XV.
  • CPRV - const PRV. CPRV hanya ada untuk kelas dan array. Non-array non-array CPRV seperti cont int akan secara implisit dikonversi ke PRV like int , misalnya sebagai imbalannya fungsi const int f() )
  • RV adalah XV atau PRV
  • CRV adalah CXV atau CPRV

Singkatan lainnya:


  • PF - Penerusan sempurna (menggunakan referensi penerusan templated untuk meneruskan parameter berfungsi)

Menetapkan kategori nilai


Penetapan kategori nilai dapat dilihat sebagai dasar dari semua bagian berikut. Ketika secara eksplisit menetapkan satu kategori ke kategori lain tanpa konversi kategori eksplisit, konversi implisit terjadi: FROM_TYPE x; TO_TYPE y; y = x; FROM_TYPE x; TO_TYPE y; y = x; Pada tabel di bawah ini Anda dapat melihat, apa yang terjadi ketika ekspresi tipe Dari ditugaskan ke variabel tipe Ke:


  • Tanda minus berarti bahwa penugasan semacam itu tidak dimungkinkan
  • Tanda tambah berarti bahwa penugasan semacam itu dimungkinkan dan tidak akan memerlukan pemanggilan operator salin / pindahkan atau konstruktor.
  • Dalam kasus lain ada teks, yang berarti operator salin / pindahkan dan konstruktor akan dipanggil selama penugasan tersebut.

Konversi, yang tidak dapat terjadi secara implisit dari kategori ekspresi yang dikembalikan ke tipe nilai pengembalian fungsi, ditandai dengan font merah - silakan lihat bagian "Kembali dari fungsi" di bawah untuk detailnya.
Garis dengan tipe konstan disorot dengan warna biru.


gambar


Catatan kaki:


1 - Referensi auto && bukan merupakan referensi penerusan, tetapi merupakan referensi yang bernilai, sehingga mereka akan bertindak seperti const T&&
2 - sementara dibuat untuk menahan penginisialisasi referensi tetap sampai akhir ruang lingkup referensi (lihat bagian berikutnya). Tidak berfungsi untuk mengonversi nilai kembali ke jenis fungsi.
3 - ketika melewati literal, perlu jenis specifier di sebelah kanan untuk otomatis: auto&& = T{2};


Catatan:


  • Referensi nilai dan nilai non-konstanta tidak dapat menerima tipe const. Tetapi non-const tipe non-referensi dapat menerima jenis const.
  • Referensi nilai (T&&) dapat menerima xvalue atau prvalue (XV atau PRV).
  • Referensi nilai (T &) dapat menerima referensi nilai atau nilai (LV atau LR)
  • Jenis non-referensi menerima jenis apa pun dengan mengonversi, menyalin, memindahkan, atau RVO
  • Tentukan nilai referensi (const T&, const auto &) dan referensi penerusan otomatis (auto &&) menerima semua jenis tanpa menyalin atau memindahkan
  • Referensi nilai konstan dan non-konstanta (T&&, const T&&) tidak dapat menerima nilai const atau non-const (LV atau CLV).
  • LR tidak dapat menerima referensi nilai const atau non-const (XV atau PRV atau CXV atau CPRV). CLR dapat menerimanya.
  • Tipe dengan const pengubah tidak dapat ditetapkan ke tipe apa pun tanpa pengubah const (kecuali otomatis, yang dapat menjadi const jika const secara eksplisit di sisi kanan).
  • Melewati nilai awal (melewati nilai balik, hasil literal atau konstruktor) sama dengan melewatkan nilai sebelumnya, tetapi menghindari pemanggilan konstruktor pemindahan saat menetapkan ke tipe non-referensi
  • Passing const prvalue (melewati nilai pengembalian fungsi type const) sama dengan passing const xvalue, tetapi menghindari pemanggilan copy constructor ketika menugaskan ke tipe non-referensi
  • Referensi otomatis dapat menjadi const, sehingga mereka dapat menerima varian const dan non-const. Juga, mereka dapat menjadi referensi const untuk membuat sementara bertahan sampai akhir ruang lingkup referensi. Tetapi referensi * otomatis tidak dapat menjadi const jika ini tidak secara eksplisit ditentukan di sisi kanan. Inilah sebabnya mengapa Anda tidak dapat menetapkan nilai untuk otomatis &
  • Referensi Const dapat menerima sementara dan membuatnya bertahan sampai akhir lingkup referensi (referensi non-const tidak dapat). Ini hanya berfungsi di dalam lingkup saat ini (referensi fungsi lokal dan argumen fungsi). Jika referensi adalah anggota kelas, objek sementara akan dihancurkan pada akhir konstruktor atau fungsi dan referensi akan terus menunjuk ke objek yang rusak, yang merupakan perilaku tidak terdefinisi.
  • Auto x = CLV; akan menyimpulkan otomatis ke tipe non-const.

Contoh dan pengujian dengan pencetakan masing-masing disebut konstruktor dan operator
 #include <iostream> #include <iomanip> #include <map> #include <vector> #include <string> using namespace std; template<class C, class T> auto contains(const C& v, const T& x) -> decltype(end(v), true) { return end(v) != std::find(begin(v), end(v), x); } template <class... Types> constexpr inline __attribute__((__always_inline__)) int UNUSED(Types&&...) { return 0; }; map<string, map<string, string>> res; vector<string> froms; vector<string> tos; string from; string to; void report(string st) { if (!from.empty() && !to.empty()) { res[from][to] += st; } cout << st << " "; } struct T { T() { report("Dc"); } T(int va) : a(va) { report("Pc"); } T(const T& other) : a(other.a) { report("Cc"); } T(T&& other) : a(std::exchange(other.a, 0)) { report("Mc"); } T& operator=(int va) { report("Va"); a = va; return *this; } T& operator=(const T& rhs) { report("Ca"); // check for self-assignment if(&rhs == this) return *this; a = rhs.a; return *this; } T& operator=(T&& rhs) { report("Ma"); // check for self-assignment if(&rhs == this) return *this; a = std::exchange(rhs.a, 0); return *this; } ~T() { report("D"); } int a = 1; }; T Fprv() { return T(); } const T Fcprv() { return T(); } void print_col(const string &st, int width) { cout << endl << left << setw(width) << st; } void test_assign(string lto, string lfrom) { from = lfrom; to = lto; res[from][to] = ""; if (!from.empty() && !to.empty()) { if (!contains(froms, from)) froms.push_back(from); if (!contains(tos, to)) tos.push_back(to); } print_col(lto + " = " + lfrom + ": ", 20); } #define TEST_ASSIGN(t, v) { \ test_assign(#t, #v); \ ts = v; \ cout << sa; \ UNUSED(s); \ cout << "-"; \ } void test_conversion() { T l; const T cl; T& lr = l; const T& clr = l; T&& rr = T(); const T&& crr = T(); auto &&fr = T(); TEST_ASSIGN(T, 8); TEST_ASSIGN(T, T()); TEST_ASSIGN(T, l); TEST_ASSIGN(T, move(l)); TEST_ASSIGN(T, cl); TEST_ASSIGN(T, move(cl)); TEST_ASSIGN(T, lr); TEST_ASSIGN(T, move(lr)); TEST_ASSIGN(T, clr); TEST_ASSIGN(T, move(clr)); TEST_ASSIGN(T, rr); TEST_ASSIGN(T, move(rr)); TEST_ASSIGN(T, crr); TEST_ASSIGN(T, move(crr)); TEST_ASSIGN(T, Fcprv()); TEST_ASSIGN(T, Fprv()); TEST_ASSIGN(T, fr); TEST_ASSIGN(T, move(fr)); TEST_ASSIGN(const T, 8); TEST_ASSIGN(const T, T()); TEST_ASSIGN(const T, l); TEST_ASSIGN(const T, move(l)); TEST_ASSIGN(const T, cl); TEST_ASSIGN(const T, move(cl)); TEST_ASSIGN(const T, lr); TEST_ASSIGN(const T, move(lr)); TEST_ASSIGN(const T, clr); TEST_ASSIGN(const T, move(clr)); TEST_ASSIGN(const T, rr); TEST_ASSIGN(const T, move(rr)); TEST_ASSIGN(const T, crr); TEST_ASSIGN(const T, move(crr)); TEST_ASSIGN(const T, Fcprv()); TEST_ASSIGN(const T, Fprv()); TEST_ASSIGN(const T, fr); TEST_ASSIGN(const T, move(fr)); //TEST_ASSIGN(T&, 8); //TEST_ASSIGN(T&, T()); TEST_ASSIGN(T&, l); //TEST_ASSIGN(T&, move(l)); //TEST_ASSIGN(T&, cl); //TEST_ASSIGN(T&, move(cl)); TEST_ASSIGN(T&, lr); //TEST_ASSIGN(T&, move(lr)); //TEST_ASSIGN(T&, clr); //TEST_ASSIGN(T&, move(clr)); //TEST_ASSIGN(T&, rr); //TEST_ASSIGN(T&, move(rr)); //TEST_ASSIGN(T&, crr); //TEST_ASSIGN(T&, move(crr)); //TEST_ASSIGN(T&, Fcprv()); //TEST_ASSIGN(T&, Fprv()); TEST_ASSIGN(T&, fr); //TEST_ASSIGN(T&, move(fr)); TEST_ASSIGN(const T&, 8); TEST_ASSIGN(const T&, T()); TEST_ASSIGN(const T&, l); TEST_ASSIGN(const T&, move(l)); TEST_ASSIGN(const T&, cl); TEST_ASSIGN(const T&, move(cl)); TEST_ASSIGN(const T&, lr); TEST_ASSIGN(const T&, move(lr)); TEST_ASSIGN(const T&, clr); TEST_ASSIGN(const T&, move(clr)); TEST_ASSIGN(const T&, rr); TEST_ASSIGN(const T&, move(rr)); TEST_ASSIGN(const T&, crr); TEST_ASSIGN(const T&, move(crr)); TEST_ASSIGN(const T&, Fcprv()); TEST_ASSIGN(const T&, Fprv()); TEST_ASSIGN(const T&, fr); TEST_ASSIGN(const T&, move(fr)); TEST_ASSIGN(T&&, 8); TEST_ASSIGN(T&&, T()); //TEST_ASSIGN(T&&, l); TEST_ASSIGN(T&&, move(l)); //TEST_ASSIGN(T&&, cl); //TEST_ASSIGN(T&&, move(cl)); //TEST_ASSIGN(T&&, lr); TEST_ASSIGN(T&&, move(lr)); //TEST_ASSIGN(T&&, clr); //TEST_ASSIGN(T&&, move(clr)); //TEST_ASSIGN(T&&, rr); TEST_ASSIGN(T&&, move(rr)); //TEST_ASSIGN(T&&, crr); //TEST_ASSIGN(T&&, move(crr)); //TEST_ASSIGN(T&&, Fcprv()); TEST_ASSIGN(T&&, Fprv()); //TEST_ASSIGN(T&&, fr); TEST_ASSIGN(T&&, move(fr)); TEST_ASSIGN(const T&&, 8); TEST_ASSIGN(const T&&, T()); //TEST_ASSIGN(const T&&, l); TEST_ASSIGN(const T&&, move(l)); //TEST_ASSIGN(const T&&, cl); TEST_ASSIGN(const T&&, move(cl)); //TEST_ASSIGN(const T&&, lr); TEST_ASSIGN(const T&&, move(lr)); //TEST_ASSIGN(const T&&, clr); TEST_ASSIGN(const T&&, move(clr)); //TEST_ASSIGN(const T&&, rr); TEST_ASSIGN(const T&&, move(rr)); //TEST_ASSIGN(const T&&, crr); TEST_ASSIGN(const T&&, move(crr)); TEST_ASSIGN(const T&&, Fcprv()); TEST_ASSIGN(const T&&, Fprv()); //TEST_ASSIGN(const T&&, fr); TEST_ASSIGN(const T&&, move(fr)); //TEST_ASSIGN(auto&, T{8}); //TEST_ASSIGN(auto&, T()); TEST_ASSIGN(auto&, l); //TEST_ASSIGN(auto&, move(l)); TEST_ASSIGN(auto&, cl); TEST_ASSIGN(auto&, move(cl)); TEST_ASSIGN(auto&, lr); //TEST_ASSIGN(auto&, move(lr)); TEST_ASSIGN(auto&, clr); TEST_ASSIGN(auto&, move(clr)); TEST_ASSIGN(auto&, rr); //TEST_ASSIGN(auto&, move(rr)); TEST_ASSIGN(auto&, crr); TEST_ASSIGN(auto&, move(crr)); TEST_ASSIGN(auto&, Fcprv()); //TEST_ASSIGN(auto&, Fprv()); TEST_ASSIGN(auto&, fr); //TEST_ASSIGN(auto&, move(fr)); TEST_ASSIGN(const auto&, T{8}); TEST_ASSIGN(const auto&, T()); TEST_ASSIGN(const auto&, l); TEST_ASSIGN(const auto&, move(l)); TEST_ASSIGN(const auto&, cl); TEST_ASSIGN(const auto&, move(cl)); TEST_ASSIGN(const auto&, lr); TEST_ASSIGN(const auto&, move(lr)); TEST_ASSIGN(const auto&, clr); TEST_ASSIGN(const auto&, move(clr)); TEST_ASSIGN(const auto&, rr); TEST_ASSIGN(const auto&, move(rr)); TEST_ASSIGN(const auto&, crr); TEST_ASSIGN(const auto&, move(crr)); TEST_ASSIGN(const auto&, Fcprv()); TEST_ASSIGN(const auto&, Fprv()); TEST_ASSIGN(const auto&, fr); TEST_ASSIGN(const auto&, move(fr)); TEST_ASSIGN(auto&&, T{8}); TEST_ASSIGN(auto&&, T()); TEST_ASSIGN(auto&&, l); TEST_ASSIGN(auto&&, move(l)); TEST_ASSIGN(auto&&, cl); TEST_ASSIGN(auto&&, move(cl)); TEST_ASSIGN(auto&&, lr); TEST_ASSIGN(auto&&, move(lr)); TEST_ASSIGN(auto&&, clr); TEST_ASSIGN(auto&&, move(clr)); TEST_ASSIGN(auto&&, rr); TEST_ASSIGN(auto&&, move(rr)); TEST_ASSIGN(auto&&, crr); TEST_ASSIGN(auto&&, move(crr)); TEST_ASSIGN(auto&&, Fcprv()); TEST_ASSIGN(auto&&, Fprv()); TEST_ASSIGN(auto&&, fr); TEST_ASSIGN(auto&&, move(fr)); TEST_ASSIGN(const auto&&, T{8}); TEST_ASSIGN(const auto&&, T()); //TEST_ASSIGN(const auto&&, l); TEST_ASSIGN(const auto&&, move(l)); //TEST_ASSIGN(const auto&&, cl); TEST_ASSIGN(const auto&&, move(cl)); //TEST_ASSIGN(const auto&&, lr); TEST_ASSIGN(const auto&&, move(lr)); //TEST_ASSIGN(const auto&&, clr); TEST_ASSIGN(const auto&&, move(clr)); //TEST_ASSIGN(const auto&&, rr); TEST_ASSIGN(const auto&&, move(rr)); //TEST_ASSIGN(const auto&&, crr); TEST_ASSIGN(const auto&&, move(crr)); TEST_ASSIGN(const auto&&, Fcprv()); TEST_ASSIGN(const auto&&, Fprv()); //TEST_ASSIGN(const auto&&, fr); TEST_ASSIGN(const auto&&, move(fr)); cout << endl; const int twidth = 9; cout << left << setw(twidth) << "From:"; for (const auto& lto : tos) { cout << left << setw(twidth) << lto; } cout << endl; for (const auto& lfrom : froms) { cout << left << setw(twidth) << lfrom; for (const auto& lto : tos) { if (!res.count(lfrom) || !res[lfrom].count(lto)) { cout << left << setw(twidth) << "-"; } else if (res[lfrom][lto].empty()) { cout << left << setw(twidth) << "+"; } else { cout << left << setw(twidth) << res[lfrom][lto]; } } cout << endl; } cout << endl; } int main() { test_conversion(); cout << endl; return 0; } /* Output: Dc Dc Dc Dc Dc T = 8: Pc 8-D T = T(): Dc 1-D T = l: Cc 1-D T = move(l): Mc 1-D T = cl: Cc 1-D T = move(cl): Cc 1-D T = lr: Cc 0-D T = move(lr): Mc 0-D T = clr: Cc 0-D T = move(clr): Cc 0-D T = rr: Cc 1-D T = move(rr): Mc 1-D T = crr: Cc 1-D T = move(crr): Cc 1-D T = Fcprv(): Dc 1-D T = Fprv(): Dc 1-D T = fr: Cc 1-D T = move(fr): Mc 1-D const T = 8: Pc 8-D const T = T(): Dc 1-D const T = l: Cc 0-D const T = move(l): Mc 0-D const T = cl: Cc 1-D const T = move(cl): Cc 1-D const T = lr: Cc 0-D const T = move(lr): Mc 0-D const T = clr: Cc 0-D const T = move(clr): Cc 0-D const T = rr: Cc 0-D const T = move(rr): Mc 0-D const T = crr: Cc 1-D const T = move(crr): Cc 1-D const T = Fcprv(): Dc 1-D const T = Fprv(): Dc 1-D const T = fr: Cc 0-D const T = move(fr): Mc 0-D T& = l: 0- T& = lr: 0- T& = fr: 0- const T& = 8: Pc 8-D const T& = T(): Dc 1-D const T& = l: 0- const T& = move(l): 0- const T& = cl: 1- const T& = move(cl): 1- const T& = lr: 0- const T& = move(lr): 0- const T& = clr: 0- const T& = move(clr): 0- const T& = rr: 0- const T& = move(rr): 0- const T& = crr: 1- const T& = move(crr): 1- const T& = Fcprv(): Dc 1-D const T& = Fprv(): Dc 1-D const T& = fr: 0- const T& = move(fr): 0- T&& = 8: Pc 8-D T&& = T(): Dc 1-D T&& = move(l): 0- T&& = move(lr): 0- T&& = move(rr): 0- T&& = Fprv(): Dc 1-D T&& = move(fr): 0- const T&& = 8: Pc 8-D const T&& = T(): Dc 1-D const T&& = move(l): 0- const T&& = move(cl): 1- const T&& = move(lr): 0- const T&& = move(clr): 0- const T&& = move(rr): 0- const T&& = move(crr): 1- const T&& = Fcprv(): Dc 1-D const T&& = Fprv(): Dc 1-D const T&& = move(fr): 0- auto& = l: 0- auto& = cl: 1- auto& = move(cl): 1- auto& = lr: 0- auto& = clr: 0- auto& = move(clr): 0- auto& = rr: 0- auto& = crr: 1- auto& = move(crr): 1- auto& = Fcprv(): Dc 1-D auto& = fr: 0- const auto& = T{8}: Pc 8-D const auto& = T(): Dc 1-D const auto& = l: 0- const auto& = move(l): 0- const auto& = cl: 1- const auto& = move(cl): 1- const auto& = lr: 0- const auto& = move(lr): 0- const auto& = clr: 0- const auto& = move(clr): 0- const auto& = rr: 0- const auto& = move(rr): 0- const auto& = crr: 1- const auto& = move(crr): 1- const auto& = Fcprv(): Dc 1-D const auto& = Fprv(): Dc 1-D const auto& = fr: 0- const auto& = move(fr): 0- auto&& = T{8}: Pc 8-D auto&& = T(): Dc 1-D auto&& = l: 0- auto&& = move(l): 0- auto&& = cl: 1- auto&& = move(cl): 1- auto&& = lr: 0- auto&& = move(lr): 0- auto&& = clr: 0- auto&& = move(clr): 0- auto&& = rr: 0- auto&& = move(rr): 0- auto&& = crr: 1- auto&& = move(crr): 1- auto&& = Fcprv(): Dc 1-D auto&& = Fprv(): Dc 1-D auto&& = fr: 0- auto&& = move(fr): 0- const auto&& = T{8}: Pc 8-D const auto&& = T(): Dc 1-D const auto&& = move(l): 0- const auto&& = move(cl): 1- const auto&& = move(lr): 0- const auto&& = move(clr): 0- const auto&& = move(rr): 0- const auto&& = move(crr): 1- const auto&& = Fcprv(): Dc 1-D const auto&& = Fprv(): Dc 1-D const auto&& = move(fr): 0- From: T const T T& const T& T&& const T&&auto& const auto&auto&& const auto&& 8 PcD PcD - PcD PcD PcD - - - - T() DcD DcD - DcD DcD DcD - DcD DcD DcD l CcD CcD + + - - + + + - move(l) McD McD - + + + - + + + cl CcD CcD - + - - + + + - move(cl) CcD CcD - + - + + + + + lr CcD CcD + + - - + + + - move(lr) McD McD - + + + - + + + clr CcD CcD - + - - + + + - move(clr)CcD CcD - + - + + + + + rr CcD CcD - + - - + + + - move(rr) McD McD - + + + - + + + crr CcD CcD - + - - + + + - move(crr)CcD CcD - + - + + + + + Fcprv() DcD DcD - DcD - DcD DcD DcD DcD DcD Fprv() DcD DcD - DcD DcD DcD - DcD DcD DcD fr CcD CcD + + - - + + + - move(fr) McD McD - + + + - + + + T{8} - - - - - - - PcD PcD PcD DDDDD */ 

Menginisialisasi referensi konstan dengan objek sementara


C ++ memungkinkan untuk menginisialisasi referensi konstan dengan objek sementara. Dalam hal ini, seumur hidup objek sementara akan diperpanjang. Contoh:


 struct T { int i = 1; }; const T& t = T(); cout << ti; 

Namun, ekstensi seumur hidup ini hanya berfungsi hingga akhir blok, tempat objek sementara dibuat. Untuk alasan ini, jika anggota referensi konstan dari sebuah kelas di inisialisasi dengan objek sementara di konstruktor, objek sementara akan dihancurkan pada akhir konstruktor dan referensi akan terus menunjuk ke objek yang rusak, yang merupakan perilaku tidak terdefinisi:


 class A { public: // Will not compile: value-initialization of reference type //A() : t() {} const T& t; }; class B { public: // Will compile in some compilers, but temporary object will be destructed at the end of constructor B() : t(T()) { cout << "In constructor: " << ti << endl; } const T& t; }; class C { public: // Will compile, but temporary object will be destructed at the end of constructor // Address sanitizer will show the problem C() : t(std::move(T())) { cout << "In constructor: " << ti << endl; } const T& t; }; C c; cout << "C: " << cti << endl; 

Tanpa pembersih alamat program ini akan mengeluarkan beberapa sampah, dan dengan pembersih alamat kesalahan akan ditampilkan. Untuk alasan ini, fitur C ++ ini tidak boleh digunakan atau harus digunakan dengan hati-hati.


Tautan:
Inisialisasi referensi
Referensi Referensi untuk Obyek Sementara
Tentang mengikat referensi const ke sub-objek sementara




Pergi ke bagian 2

Source: https://habr.com/ru/post/id479342/


All Articles