C ++ adalah tentang kepemilikan memori - alias semantik kepemilikan .
Ini adalah tanggung jawab pemilik sebagian dari memori yang dialokasikan secara dinamis untuk melepaskan memori itu. Jadi pertanyaannya sebenarnya menjadi siapa yang memiliki ingatan.
Dalam C ++, kepemilikan didokumentasikan oleh jenis pointer mentah yang dibungkus di dalamnya sehingga dalam program C ++ yang baik (IMO) sangat jarang ( jarang , tidak pernah ) untuk melihat pointer mentah diedarkan (karena pointer mentah tidak memiliki kepemilikan yang disimpulkan sehingga kita bisa tidak memberi tahu siapa yang memiliki memori dan dengan demikian tanpa membaca dokumentasi dengan cermat, Anda tidak dapat mengetahui siapa yang bertanggung jawab atas kepemilikan).
Sebaliknya, sangat jarang untuk melihat pointer mentah disimpan di kelas setiap pointer mentah disimpan dalam bungkus smart pointer-nya sendiri. ( NB: Jika Anda tidak memiliki objek, Anda tidak boleh menyimpannya karena Anda tidak dapat mengetahui kapan objek itu akan keluar dari ruang lingkup dan dimusnahkan.)
Jadi pertanyaannya:
- Jenis kepemilikan semantik apa yang sering ditemukan orang?
- Kelas standar apa yang digunakan untuk mengimplementasikan semantik tersebut?
- Dalam situasi apa Anda menganggapnya berguna?
Mari kita pertahankan 1 jenis kepemilikan semantik per jawaban sehingga dapat dipilih naik turun secara individual.
Ringkasan:
Secara konseptual, petunjuk cerdas itu sederhana dan implementasi yang naif itu mudah. Saya telah melihat banyak penerapan percobaan, tetapi selalu gagal dalam beberapa cara yang tidak jelas untuk penggunaan dan contoh biasa. Oleh karena itu, saya sarankan untuk selalu menggunakan petunjuk cerdas yang teruji dengan baik dari perpustakaan daripada menggulirkannya sendiri. std::auto_ptr
atau salah satu petunjuk cerdas Boost sepertinya memenuhi semua kebutuhan saya.
std::auto_ptr<T>
:
Orang lajang memiliki objek tersebut. Transfer kepemilikan diperbolehkan.
Penggunaan: Ini memungkinkan Anda untuk menentukan antarmuka yang menunjukkan transfer kepemilikan secara eksplisit.
boost::scoped_ptr<T>
Orang lajang memiliki objek tersebut. Transfer kepemilikan TIDAK diperbolehkan.
Penggunaan: Digunakan untuk menunjukkan kepemilikan eksplisit. Objek akan dihancurkan oleh destruktor atau saat disetel ulang secara eksplisit.
boost::shared_ptr<T>
( std::tr1::shared_ptr<T>
)
Kepemilikan ganda. Ini adalah referensi pointer terhitung sederhana. Saat jumlah referensi mencapai nol, objek dimusnahkan.
Kegunaan: Ketika suatu objek dapat memiliki banyak bunga dengan masa pakai yang tidak dapat ditentukan pada waktu kompilasi.
boost::weak_ptr<T>
:
Digunakan dengan shared_ptr<T>
situasi di mana siklus petunjuk mungkin terjadi.
Penggunaan: Digunakan untuk menghentikan siklus dari mempertahankan objek ketika hanya siklus yang mempertahankan refcount bersama.
sumber
In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good (IMO)
Bisakah ini diubah? Saya tidak mengerti sama sekali.In C++ ownership is documented by the type a RAW pointer is wrapped inside thus in a good C++ program it is very rare to see RAW pointers passed around
. Penunjuk RAW tidak memiliki semantik kepemilikan. Jika Anda tidak mengetahui pemiliknya, Anda tidak tahu siapa yang bertanggung jawab untuk menghapus objek. Ada beberapa kelas standar yang digunakan untuk membungkus pointer (std :: shared_ptr, std :: unique_ptr dll) yang mendefinisikan kepemilikan dan karenanya tentukan siapa yang bertanggung jawab untuk menghapus penunjuk.Jawaban:
Bagi saya, 3 jenis ini memenuhi sebagian besar kebutuhan saya:
shared_ptr
- referensi dihitung, deallocation saat penghitung mencapai nolweak_ptr
- sama seperti di atas, tetapi ini adalah 'budak' untuk ashared_ptr
, tidak dapat membatalkan alokasiauto_ptr
- saat pembuatan dan pelepasan alokasi terjadi di dalam fungsi yang sama, atau saat objek harus dianggap hanya satu-pemilik. Saat Anda menetapkan satu penunjuk ke penunjuk lainnya, penunjuk kedua 'mencuri' objek dari penunjuk pertama.Saya memiliki penerapan sendiri untuk ini, tetapi mereka juga tersedia di
Boost
.Saya masih meneruskan objek dengan referensi (
const
bila memungkinkan), dalam hal ini metode yang dipanggil harus menganggap objek tersebut hidup hanya selama waktu panggilan.Ada jenis pointer lain yang saya gunakan yang saya sebut hub_ptr . Itu ketika Anda memiliki objek yang harus dapat diakses dari objek yang bersarang di dalamnya (biasanya sebagai kelas basis virtual). Ini bisa diselesaikan dengan memberikan
weak_ptr
kepada mereka, tetapi tidak harusshared_ptr
itu sendiri. Karena ia tahu objek ini tidak akan hidup lebih lama darinya, ia meneruskan hub_ptr ke mereka (itu hanya pembungkus template ke penunjuk biasa).sumber
noncopyable
dan kepemilikan tidak dapat dialihkan.Model C ++ sederhana
Di sebagian besar modul yang saya lihat, secara default, diasumsikan bahwa penerima petunjuk tidak menerima kepemilikan. Faktanya, fungsi / metode yang mengabaikan kepemilikan pointer sangat jarang dan secara eksplisit mengungkapkan fakta tersebut dalam dokumentasinya.
Model ini mengasumsikan bahwa pengguna adalah pemilik hanya dari apa yang dia alokasikan secara eksplisit . Segala sesuatu yang lain secara otomatis dibuang (saat keluar ruang lingkup, atau melalui RAII). Ini adalah model mirip-C, diperluas oleh fakta bahwa kebanyakan pointer dimiliki oleh objek yang akan membatalkan alokasinya secara otomatis atau ketika dibutuhkan (pada penghancuran objek tersebut, sebagian besar), dan bahwa durasi hidup objek dapat diprediksi (RAII adalah teman Anda, lagi).
Dalam model ini, petunjuk mentah beredar bebas dan sebagian besar tidak berbahaya (tetapi jika pengembang cukup pintar, dia akan menggunakan referensi sebagai gantinya bila memungkinkan).
Model C ++ Menunjuk Cerdas
Dalam kode yang penuh dengan petunjuk cerdas, pengguna dapat berharap untuk mengabaikan masa pakai objek. Pemilik tidak pernah menjadi kode pengguna: Ini adalah penunjuk cerdas itu sendiri (RAII, sekali lagi). Masalahnya adalah bahwa referensi melingkar yang dicampur dengan referensi yang dihitung sebagai petunjuk pintar bisa mematikan , jadi Anda harus berurusan dengan petunjuk bersama dan petunjuk lemah. Jadi Anda masih memiliki kepemilikan untuk dipertimbangkan (penunjuk yang lemah bisa jadi tidak menunjukkan apa-apa, bahkan jika keuntungannya dibandingkan penunjuk mentah adalah ia dapat memberitahu Anda demikian).
Kesimpulan
Tidak peduli model yang saya gambarkan, kecuali, menerima pointer tidak menerima kepemilikannya dan masih sangat penting untuk mengetahui siapa yang memiliki siapa . Bahkan untuk kode C ++ banyak menggunakan referensi dan / atau petunjuk cerdas.
sumber
Tidak memiliki kepemilikan bersama. Jika Anda melakukannya, pastikan hanya dengan kode yang tidak Anda kontrol.
Itu menyelesaikan 100% masalah, karena memaksa Anda untuk memahami bagaimana segala sesuatu berinteraksi.
sumber
Saat sumber daya dibagikan di antara beberapa objek. Peningkatan shared_ptr menggunakan penghitungan referensi untuk memastikan sumber daya dibatalkan alokasi ketika semua orang selesai.
sumber
std::tr1::shared_ptr<Blah>
sering kali merupakan taruhan terbaik Anda.sumber
Dari boost, ada juga wadah penunjuk pustaka . Ini sedikit lebih efisien dan lebih mudah digunakan daripada wadah standar pointer pintar, jika Anda hanya akan menggunakan objek dalam konteks wadahnya.
Di Windows, terdapat penunjuk COM (IUnknown, IDispatch, dan teman), dan berbagai penunjuk cerdas untuk menanganinya (misalnya CComPtr ATL dan penunjuk pintar yang dihasilkan secara otomatis oleh pernyataan "impor" di Visual Studio berdasarkan kelas _com_ptr ).
sumber
Saat Anda perlu mengalokasikan memori secara dinamis tetapi ingin memastikannya dialokasikan pada setiap titik keluar blok.
Saya menemukan ini berguna karena dapat dengan mudah diulang, dan dirilis tanpa harus khawatir tentang kebocoran
sumber
Saya rasa saya tidak pernah berada dalam posisi untuk berbagi kepemilikan dalam desain saya. Faktanya, dari atas kepala saya satu-satunya kasus valid yang dapat saya pikirkan adalah pola Kelas Terbang.
sumber
yasper :: ptr adalah alternatif yang ringan, boost :: shared_ptr. Ini bekerja dengan baik dalam proyek kecil saya (untuk saat ini).
Di halaman web di http://yasper.sourceforge.net/ dijelaskan sebagai berikut:
sumber
Ada bentuk lain yang sering digunakan dari pemilik tunggal yang dapat dialihkan, dan ini lebih disukai
auto_ptr
karena menghindari masalah yang disebabkan olehauto_ptr
korupsi semantik tugas yang tidak wajar.Saya berbicara tidak lain adalah
swap
. Jenis apa pun denganswap
fungsi yang sesuai dapat dipahami sebagai referensi cerdas untuk beberapa konten, yang dimilikinya hingga saat kepemilikan ditransfer ke instance lain dari jenis yang sama, dengan menukarnya. Setiap instance mempertahankan identitasnya tetapi terikat ke konten baru. Ini seperti referensi yang dapat ditarik kembali dengan aman.(Ini adalah referensi cerdas daripada penunjuk cerdas karena Anda tidak perlu secara eksplisit membedakannya untuk mendapatkan konten.)
Ini berarti auto_ptr menjadi kurang diperlukan - ini hanya diperlukan untuk mengisi celah di mana tipe tidak memiliki
swap
fungsi yang baik . Tetapi semua kontainer standar melakukannya.sumber
Ketika pencipta objek ingin secara eksplisit menyerahkan kepemilikan kepada orang lain. Ini juga cara mendokumentasikan kode yang saya berikan kepada Anda dan saya tidak lagi melacaknya, jadi pastikan Anda menghapusnya setelah selesai.
sumber