Ok, jadi terakhir kali saya menulis C ++ untuk mencari nafkah, std::auto_ptr
adalah semua std lib telah tersedia, dan boost::shared_ptr
semua adalah kemarahan. Saya tidak pernah benar-benar melihat ke dalam tipe penunjuk pintar lainnya yang disediakan. Saya mengerti bahwa C ++ 11 sekarang menyediakan beberapa tipe boost, tetapi tidak semuanya.
Jadi apakah seseorang memiliki algoritma sederhana untuk menentukan kapan harus menggunakan smart pointer? Lebih disukai termasuk saran tentang pointer bodoh (pointer mentah seperti T*
) dan sisa pointer pintar meningkatkan. (Sesuatu seperti ini akan bagus).
Jawaban:
Kepemilikan bersama:
Standar
shared_ptr
danweak_ptr
yang diadopsi hampir sama dengan rekan Boost mereka . Gunakan mereka ketika Anda perlu berbagi sumber daya dan tidak tahu mana yang akan menjadi yang terakhir untuk hidup. Gunakanweak_ptr
untuk mengamati sumber daya bersama tanpa mempengaruhi masa pakainya, bukan untuk memutus siklus. Siklus denganshared_ptr
seharusnya tidak terjadi - dua sumber daya tidak dapat memiliki satu sama lain.Perhatikan bahwa Boost juga menawarkan
shared_array
, yang mungkin merupakan alternatif yang cocok untukshared_ptr<std::vector<T> const>
.Selanjutnya, Boost menawarkan
intrusive_ptr
, yang merupakan solusi ringan jika sumber daya Anda sudah menawarkan manajemen yang dihitung referensi dan Anda ingin mengadopsinya dengan prinsip RAII. Yang ini tidak diadopsi oleh standar.Kepemilikan unik:
Boost juga memiliki
scoped_ptr
, yang tidak dapat disalin dan Anda tidak dapat menentukan deleter.std::unique_ptr
adalahboost::scoped_ptr
pada steroid dan harus Anda pilihan default ketika Anda membutuhkan pointer pintar . Ini memungkinkan Anda untuk menentukan deleter dalam argumen templatnya dan dapat dipindah , tidak sepertiboost::scoped_ptr
. Ini juga sepenuhnya dapat digunakan dalam wadah STL selama Anda tidak menggunakan operasi yang membutuhkan jenis yang dapat disalin (jelas).Perhatikan lagi, bahwa Boost memiliki versi larik:,
scoped_array
yang standar disatukan dengan memerlukanstd::unique_ptr<T[]>
spesialisasi parsial yang akandelete[]
mengarahkan bukan penunjukdelete
(dengandefault_delete
r).std::unique_ptr<T[]>
juga menawarkanoperator[]
bukanoperator*
danoperator->
.Perhatikan bahwa
std::auto_ptr
masih dalam standar, tetapi sudah usang .§D.10 [depr.auto.ptr]
Tanpa kepemilikan:
Gunakan pointer bodoh (pointer mentah) atau referensi untuk referensi yang tidak memiliki sumber daya dan ketika Anda tahu bahwa sumber daya akan hidup lebih lama dari objek referensi / ruang lingkup. Lebih suka referensi dan gunakan pointer mentah ketika Anda membutuhkan nullability atau resettability.
Jika Anda ingin referensi yang tidak memiliki sumber daya, tetapi Anda tidak tahu apakah sumber daya akan hidup lebih lama dari objek yang mereferensikannya, kemas sumber daya itu dalam
shared_ptr
dan gunakan aweak_ptr
- Anda dapat menguji apakah induknyashared_ptr
masih hiduplock
, yang akan mengembalikanshared_ptr
yang bukan nol jika sumber daya masih ada. Jika ingin menguji apakah sumber daya sudah mati, gunakanexpired
. Keduanya mungkin terdengar serupa, tetapi sangat berbeda dalam menghadapi eksekusi bersamaan, karenaexpired
hanya menjamin nilai kembalinya untuk pernyataan tunggal itu. Tes yang tampaknya tidak bersalah sepertiadalah kondisi lomba yang potensial.
sumber
shared_ptr
dan pointer yang tidak memiliki menjadi aweak_ptr
...shared_array<T>
adalah alternatif untukshared_ptr<T[]>
tidakshared_ptr<vector<T>>
: itu tidak bisa tumbuh.Menentukan penunjuk pintar apa yang akan digunakan adalah masalah kepemilikan . Ketika datang ke manajemen sumber daya, objek A memiliki objek B jika ia mengendalikan masa objek B. Misalnya, variabel anggota dimiliki oleh objek masing-masing karena masa hidup variabel anggota terkait dengan masa pakai objek. Anda memilih pointer pintar berdasarkan pada bagaimana objek dimiliki.
Perhatikan bahwa kepemilikan dalam sistem perangkat lunak terpisah dari kepemilikan karena kami akan menganggapnya di luar perangkat lunak. Misalnya, seseorang mungkin "memiliki" rumah mereka, tetapi itu tidak berarti bahwa suatu
Person
objek memiliki kendali atas masa hidup suatuHouse
objek. Menggabungkan konsep-konsep dunia nyata ini dengan konsep perangkat lunak adalah cara yang pasti untuk memprogram diri Anda menjadi sebuah lubang.Jika Anda memiliki kepemilikan tunggal atas objek tersebut, gunakan
std::unique_ptr<T>
.Jika Anda telah berbagi kepemilikan atas objek ...
- Jika tidak ada siklus kepemilikan, gunakan
std::shared_ptr<T>
.- Jika ada siklus, tentukan "arah" dan gunakan
std::shared_ptr<T>
dalam satu arah danstd::weak_ptr<T>
lainnya.Jika objek memiliki Anda, tetapi ada kemungkinan tidak memiliki pemilik, gunakan pointer normal
T*
(misal pointer orangtua).Jika objek memiliki Anda (atau keberadaannya dijamin), gunakan referensi
T&
.Peringatan: Waspadai biaya petunjuk pintar. Dalam lingkungan terbatas memori atau kinerja, mungkin bermanfaat untuk hanya menggunakan pointer normal dengan skema yang lebih manual untuk mengelola memori.
Biaya:
std::shared_ptr
memiliki overhead dari kenaikan jumlah referensi pada salinan, ditambah penurunan pada penghancuran diikuti oleh cek 0-hitungan dengan penghapusan objek yang ditahan. Bergantung pada implementasinya, ini dapat mengasapi kode Anda dan menyebabkan masalah kinerja.Contoh:
Pohon biner tidak memiliki induknya, tetapi keberadaan pohon menyiratkan keberadaan induknya (atau
nullptr
untuk root), sehingga menggunakan pointer normal. Pohon biner (dengan semantik nilai) memiliki kepemilikan tunggal atas anak-anaknya, demikian pula merekastd::unique_ptr
.Di sini, simpul daftar memiliki daftar berikutnya dan sebelumnya, jadi kami menentukan arah dan digunakan
shared_ptr
untuk selanjutnya danweak_ptr
untuk mematahkan siklus.sumber
shared_ptr<BinaryTree>
untuk anak-anak danweak_ptr<BinaryTree>
untuk hubungan orang tua.Gunakan
unique_ptr<T>
sepanjang waktu kecuali ketika Anda membutuhkan penghitungan referensi, dalam hal ini penggunaanshared_ptr<T>
(dan untuk kasus yang sangat jarang,weak_ptr<T>
untuk mencegah siklus referensi). Dalam hampir setiap kasus, kepemilikan unik yang dapat ditransfer tidak masalah.Pointer mentah: Bagus hanya jika Anda membutuhkan pengembalian kovarian, penunjukan tidak memiliki yang bisa terjadi. Sebaliknya mereka tidak terlalu berguna.
Array pointer:
unique_ptr
memiliki spesialisasiT[]
yang secara otomatis memanggildelete[]
hasilnya, sehingga Anda dapat melakukannya dengan amanunique_ptr<int[]> p(new int[42]);
misalnya.shared_ptr
Anda masih memerlukan deleter khusus, tetapi Anda tidak memerlukan pointer array khusus yang dibagikan atau unik. Tentu saja, hal-hal seperti itu biasanya paling baik digantistd::vector
. Sayangnyashared_ptr
tidak menyediakan fungsi akses array, jadi Anda masih harus menelepon secara manualget()
, tetapiunique_ptr<T[]>
menyediakanoperator[]
alih-alihoperator*
danoperator->
. Bagaimanapun, Anda harus memeriksa diri Anda sendiri. Ini membuatshared_ptr
sedikit kurang ramah pengguna, meskipun bisa dibilang keunggulan generik dan tidak ada ketergantungan Boost membuatunique_ptr
danshared_ptr
pemenang lagi.Petunjuk lingkup: Dibuat tidak relevan oleh
unique_ptr
, sama sepertiauto_ptr
.Tidak ada yang lebih dari itu. Dalam C ++ 03 tanpa memindahkan semantik situasi ini sangat rumit, tetapi dalam C ++ 11 sarannya sangat sederhana.
Masih ada penggunaan untuk pointer pintar lainnya, seperti
intrusive_ptr
atauinterprocess_ptr
. Namun, mereka sangat niche dan sama sekali tidak perlu dalam kasus umum.sumber
std::unique_ptr<T[]>
menyediakanoperator[]
bukanoperator*
danoperator->
. Memang benar bahwa Anda masih perlu melakukan pengecekan diri sendiri.Kasus kapan harus digunakan
unique_ptr
:Kasus kapan harus digunakan
shared_ptr
:Kasus kapan harus digunakan
weak_ptr
:Merasa bebas untuk mengedit dan menambahkan lebih banyak
sumber