Ini adalah contoh sederhana untuk mengilustrasikan pertanyaan:
class A {};
class B
{
B(A& a) : a(a) {}
A& a;
};
class C
{
C() : b(a) {}
A a;
B b;
};
Jadi B bertanggung jawab untuk memperbarui bagian dari C. Saya menjalankan kode melalui lint dan bertanya tentang anggota referensi: lint # 1725 . Ini berbicara tentang mengurus salinan default dan tugas yang cukup adil, tetapi salinan default dan tugas juga buruk dengan petunjuk, jadi ada sedikit keuntungan di sana.
Saya selalu mencoba menggunakan referensi di mana saya bisa karena pointer telanjang memperkenalkan secara tidak pasti tentang siapa yang bertanggung jawab untuk menghapus pointer itu. Saya lebih suka menyematkan objek berdasarkan nilai tetapi jika saya membutuhkan pointer, saya menggunakan auto_ptr di data anggota kelas yang memiliki pointer, dan meneruskan objek tersebut sebagai referensi.
Saya biasanya hanya akan menggunakan pointer dalam data anggota ketika pointer bisa menjadi null atau bisa berubah. Apakah ada alasan lain untuk lebih memilih petunjuk daripada referensi untuk anggota data?
Benarkah untuk mengatakan bahwa objek yang berisi referensi tidak boleh dialihkan, karena referensi tidak boleh diubah setelah diinisialisasi?
sumber
Jawaban:
Hindari anggota referensi, karena mereka membatasi apa yang dapat dilakukan oleh implementasi kelas (termasuk, seperti yang Anda sebutkan, mencegah implementasi operator tugas) dan tidak memberikan manfaat pada apa yang dapat disediakan kelas.
Contoh soal:
hingga C ++ 0x, tetap sajaedit: C ++ sekarang memiliki konstruktor yang mendelegasikan ).
operator dll), tetapi berperilaku seperti penunjuk (dapat menjuntai) - jadi misalnya, Panduan Gaya Google melarangnyasumber
Aturan praktis saya sendiri:
sumber
Objek jarang harus memungkinkan menetapkan dan hal-hal lain seperti perbandingan. Jika Anda mempertimbangkan beberapa model bisnis dengan objek seperti 'Departemen', 'Karyawan', 'Direktur', sulit membayangkan sebuah kasus ketika satu karyawan akan ditugaskan ke yang lain.
Jadi untuk objek bisnis, sangat baik untuk mendeskripsikan hubungan satu-ke-satu dan satu-ke-banyak sebagai referensi dan bukan penunjuk.
Dan mungkin tidak masalah untuk mendeskripsikan hubungan satu atau nol sebagai penunjuk.
Jadi tidak ada 'kami tidak dapat menetapkan' maka faktor.
Banyak programmer yang terbiasa dengan pointer dan itulah mengapa mereka akan menemukan argumen untuk menghindari penggunaan referensi.
Memiliki pointer sebagai anggota akan memaksa Anda atau anggota tim Anda untuk memeriksa pointer berulang kali sebelum digunakan, dengan komentar "berjaga-jaga". Jika sebuah pointer bisa menjadi nol maka pointer mungkin digunakan sebagai jenis bendera, yang buruk, karena setiap objek harus memainkan perannya sendiri.
sumber
Gunakan referensi saat Anda bisa, dan petunjuk saat Anda harus.
sumber
Dalam beberapa kasus penting, penugasan sama sekali tidak diperlukan. Ini seringkali merupakan pembungkus algoritme ringan yang memfasilitasi kalkulasi tanpa meninggalkan ruang lingkup. Objek tersebut adalah kandidat utama untuk anggota referensi karena Anda dapat yakin bahwa objek tersebut selalu memiliki referensi yang valid dan tidak perlu disalin.
Dalam kasus seperti itu, pastikan untuk membuat operator penugasan (dan seringkali juga konstruktor salinan) tidak dapat digunakan (dengan mewarisi dari
boost::noncopyable
atau mendeklarasikannya sebagai pribadi).Namun, karena poin pengguna telah dikomentari, hal yang sama tidak berlaku untuk sebagian besar objek lainnya. Di sini, menggunakan anggota referensi bisa menjadi masalah besar dan umumnya harus dihindari.
sumber
Karena semua orang tampaknya membagikan aturan umum, saya akan menawarkan dua:
Jangan sekali-kali menggunakan rujukan sebagai anggota kelas. Saya tidak pernah melakukannya dalam kode saya sendiri (kecuali untuk membuktikan kepada diri saya sendiri bahwa saya benar dalam aturan ini) dan tidak dapat membayangkan kasus di mana saya akan melakukannya. Semantiknya terlalu membingungkan, dan itu sebenarnya bukan untuk apa referensi dirancang.
Selalu, selalu, gunakan referensi saat meneruskan parameter ke fungsi, kecuali untuk tipe dasar, atau saat algoritme memerlukan salinan.
Aturan-aturan ini sederhana, dan mendukung saya. Saya meninggalkan membuat aturan tentang penggunaan pointer pintar (tapi tolong, bukan auto_ptr) sebagai anggota kelas kepada orang lain.
sumber
Ya untuk: Apakah benar mengatakan bahwa objek yang berisi referensi tidak boleh dialihkan, karena referensi tidak boleh diubah setelah diinisialisasi?
Aturan praktis saya untuk anggota data:
sumber
Iya. Keterbacaan kode Anda. Sebuah pointer membuatnya lebih jelas bahwa anggota adalah referensi (ironisnya :)), dan bukan objek yang terkandung, karena ketika Anda menggunakannya, Anda harus membatalkan referensi itu. Saya tahu beberapa orang berpikir itu kuno, tetapi saya masih berpikir bahwa itu hanya mencegah kebingungan dan kesalahan.
sumber
Saya tidak menyarankan anggota data referensi karena Anda tidak pernah tahu siapa yang akan berasal dari kelas Anda dan apa yang mungkin ingin mereka lakukan. Mereka mungkin tidak ingin menggunakan objek yang direferensikan, tetapi menjadi referensi Anda telah memaksa mereka untuk memberikan objek yang valid. Saya telah melakukan ini sendiri cukup untuk berhenti menggunakan anggota data referensi.
sumber
Jika saya memahami pertanyaan dengan benar ...
Referensi sebagai parameter fungsi alih-alih pointer: Seperti yang Anda tunjukkan, pointer tidak menjelaskan siapa yang memiliki pembersihan / inisialisasi pointer. Lebih suka titik bersama ketika Anda menginginkan sebuah pointer, itu adalah bagian dari C ++ 11, dan weak_ptr ketika validitas data tidak dijamin selama masa kelas menerima menunjuk ke data .; juga merupakan bagian dari C ++ 11. Menggunakan referensi sebagai parameter fungsi menjamin bahwa referensi tersebut tidak null. Anda harus menumbangkan fitur bahasa untuk menyiasati ini, dan kami tidak peduli dengan pembuat kode meriam lepas.
Referensi variabel anggota: Seperti di atas dalam hal validitas data. Ini menjamin bahwa data yang diarahkan ke data, kemudian direferensikan, valid.
Memindahkan tanggung jawab validitas variabel ke poin sebelumnya dalam kode tidak hanya membersihkan kode selanjutnya (kelas A dalam contoh Anda), tetapi juga menjelaskannya kepada orang yang menggunakan.
Dalam contoh Anda, yang agak membingungkan (saya benar-benar akan mencoba menemukan implementasi yang lebih jelas), A yang digunakan oleh B dijamin seumur hidup B, karena B adalah anggota A, jadi referensi memperkuat ini dan (mungkin) lebih jelas.
Dan untuk berjaga-jaga (yang kemungkinannya rendah karena tidak masuk akal dalam konteks kode Anda), alternatif lain, menggunakan parameter A non referensi, non penunjuk, akan menyalin A, dan membuat paradigma tidak berguna - I benar-benar tidak berpikir yang Anda maksud ini sebagai alternatif.
Selain itu, ini juga menjamin Anda tidak dapat mengubah data yang direferensikan, di mana penunjuk dapat dimodifikasi. Sebuah pointer const akan bekerja, hanya jika direferensikan / pointer ke data tidak bisa berubah.
Pointer berguna jika parameter A untuk B tidak dijamin akan disetel, atau dapat ditetapkan ulang. Dan terkadang penunjuk lemah terlalu bertele-tele untuk implementasi, dan banyak orang yang tidak tahu apa itu weak_ptr, atau hanya tidak menyukai mereka.
Sobek jawaban ini, tolong :)
sumber