Apakah boleh delete this;
jika pernyataan delete adalah pernyataan terakhir yang akan dieksekusi pada instance kelas itu? Tentu saja saya yakin bahwa objek yang diwakili oleh this
-pointer new
dibuat.
Saya sedang memikirkan sesuatu seperti ini:
void SomeModule::doStuff()
{
// in the controller, "this" object of SomeModule is the "current module"
// now, if I want to switch over to a new Module, eg:
controller->setWorkingModule(new OtherModule());
// since the new "OtherModule" object will take the lead,
// I want to get rid of this "SomeModule" object:
delete this;
}
Bisakah saya melakukan ini?
c++
memory-management
new-operator
delete-operator
self-destruction
Martijn Courteaux
sumber
sumber
delete this
telah membuat kopling ketat antara kelas dan metode alokasi yang digunakan untuk membuat objek dari kelas itu. Itu adalah desain OO yang sangat buruk, karena hal yang paling mendasar dalam OOP adalah membuat kelas otonom yang tidak tahu atau peduli tentang apa yang dilakukan penelepon mereka. Dengan demikian kelas yang dirancang dengan baik seharusnya tidak tahu atau peduli tentang bagaimana itu dialokasikan. Jika Anda karena suatu alasan memerlukan mekanisme yang aneh, saya pikir desain yang lebih baik adalah dengan menggunakan kelas pembungkus di sekitar kelas yang sebenarnya, dan biarkan pembungkus berurusan dengan alokasi.setWorkingModule
?Jawaban:
C ++ FAQ Lite memiliki entri khusus untuk ini
Saya pikir kutipan ini merangkumnya dengan baik
sumber
Ya,
delete this;
telah menetapkan hasil, selama (seperti yang telah Anda catat), Anda memastikan objek dialokasikan secara dinamis, dan (tentu saja) tidak pernah mencoba menggunakan objek setelah dihancurkan. Selama bertahun-tahun, banyak pertanyaan telah diajukan tentang apa yang standar katakan secara spesifikdelete this;
, sebagai lawan menghapus beberapa pointer lainnya. Jawabannya cukup singkat dan sederhana: tidak banyak bicara. Itu hanya mengatakan bahwadelete
operan harus berupa ekspresi yang menunjuk pointer ke objek, atau array objek. Ini masuk ke sedikit detail tentang hal-hal seperti bagaimana mencari tahu apa fungsidelete
deallokasi (jika ada) untuk memanggil untuk melepaskan memori, tetapi seluruh bagian pada (§ [expr.delete]) tidak menyebutkandelete this;
secara khusus sama sekali. Bagian tentang penghancur menyebutkandelete this
di satu tempat (§ [class.dtor] / 13):Itu cenderung mendukung gagasan yang dianggap standar sebagai
delete this;
valid - jika tidak valid, tipenya tidak akan berarti. Itu satu-satunya tempat yang disebutkan standardelete this;
sama sekali, sejauh yang saya tahu.Bagaimanapun, beberapa orang menganggap
delete this
peretasan tidak baik, dan memberi tahu siapa pun yang akan mendengarkan bahwa itu harus dihindari. Satu masalah yang sering dikutip adalah kesulitan memastikan bahwa objek kelas hanya dialokasikan secara dinamis. Orang lain menganggapnya sebagai ungkapan yang sangat masuk akal, dan menggunakannya sepanjang waktu. Secara pribadi, saya di suatu tempat di tengah: Saya jarang menggunakannya, tetapi jangan ragu untuk melakukannya ketika itu tampaknya menjadi alat yang tepat untuk pekerjaan itu.Waktu utama Anda menggunakan teknik ini adalah dengan objek yang memiliki kehidupan yang hampir seluruhnya miliknya. Satu contoh yang dikutip oleh James Kanze adalah sistem penagihan / pelacakan yang ia kerjakan untuk perusahaan telepon. Ketika Anda mulai membuat panggilan telepon, ada yang memperhatikan hal itu dan membuat
phone_call
objek. Sejak saat itu,phone_call
objek menangani detail panggilan telepon (membuat koneksi saat Anda melakukan panggilan, menambahkan entri ke database untuk mengatakan kapan panggilan dimulai, mungkin menghubungkan lebih banyak orang jika Anda melakukan panggilan konferensi, dll.) orang terakhir yang dipanggil menutup telepon,phone_call
objek melakukan pembukuan terakhirnya (mis., menambahkan entri ke database untuk mengatakan kapan Anda menutup telepon, sehingga mereka dapat menghitung berapa lama panggilan Anda) dan kemudian menghancurkan dirinya sendiri. Seumur hidupphone_call
objek didasarkan pada ketika orang pertama memulai panggilan dan ketika orang terakhir meninggalkan panggilan - dari sudut pandang sisa sistem, itu pada dasarnya sepenuhnya arbitrer, jadi Anda tidak dapat mengikatnya ke lingkup leksikal dalam kode , atau apa pun di pesanan itu.Bagi siapa pun yang mungkin peduli tentang seberapa dapat diandalkannya pengkodean semacam ini: jika Anda melakukan panggilan telepon ke, dari, atau melalui hampir semua bagian Eropa, ada peluang yang cukup bagus bahwa kode itu ditangani (setidaknya sebagian) dengan kode itu tidak persis seperti ini.
sumber
bool selfDelete
parameter dalam konstruktor yang ditugaskan ke variabel anggota. Memang, ini berarti menyerahkan tali programmer cukup untuk mengikat tali di dalamnya, tapi saya menemukan bahwa lebih baik kebocoran memori.this
. Ya, kode tersebut ditangani dengan tepatthis
. ;)Jika itu membuat Anda takut, ada peretasan legal:
Saya pikir
delete this
ini C ++ idiomatis, dan saya hanya menyajikan ini sebagai rasa ingin tahu.Ada kasus di mana konstruksi ini sebenarnya berguna - Anda dapat menghapus objek setelah melemparkan pengecualian yang membutuhkan data anggota dari objek. Objek tetap valid sampai setelah lemparan berlangsung.
Catatan: jika Anda menggunakan kompiler yang lebih tua dari C ++ 11 yang dapat Anda gunakan
std::auto_ptr
sebagai gantinyastd::unique_ptr
, itu akan melakukan hal yang sama.sumber
unique_ptr
dari yang lainunique_ptr
membutuhkan gerakan, tetapi bukan dari pointer mentah. Kecuali hal-hal berubah dalam C ++ 17?Salah satu alasan mengapa C ++ dirancang adalah untuk membuatnya mudah untuk menggunakan kembali kode. Secara umum, C ++ harus ditulis sehingga berfungsi apakah kelas dipakai pada heap, dalam array, atau pada stack. "Hapus ini" adalah praktik pengkodean yang sangat buruk karena hanya akan berfungsi jika satu instance didefinisikan pada heap; dan lebih baik tidak ada pernyataan penghapusan lain, yang biasanya digunakan oleh sebagian besar pengembang untuk membersihkan tumpukan. Melakukan hal ini juga mengasumsikan bahwa tidak ada programmer pemeliharaan di masa depan yang akan menyembuhkan kebocoran memori yang dirasakan salah dengan menambahkan pernyataan hapus.
Bahkan jika Anda tahu sebelumnya bahwa rencana Anda saat ini adalah hanya mengalokasikan satu instance pada heap, bagaimana jika beberapa pengembang happy-go-lucky datang di masa depan dan memutuskan untuk membuat instance di stack? Atau, bagaimana jika dia memotong dan menempel bagian-bagian tertentu dari kelas ke kelas baru yang ingin dia gunakan di tumpukan? Ketika kode mencapai "hapus ini" itu akan pergi dan menghapusnya, tetapi kemudian ketika objek keluar dari ruang lingkup, itu akan memanggil destruktor. Destructor kemudian akan mencoba untuk menghapusnya lagi dan kemudian Anda disemprot. Di masa lalu, melakukan sesuatu seperti ini akan mengacaukan tidak hanya program tetapi sistem operasi dan komputer perlu di-boot ulang. Bagaimanapun, ini sangat TIDAK dianjurkan dan hampir selalu harus dihindari. Saya harus putus asa, terpampang serius,
sumber
Itu diperbolehkan (hanya jangan menggunakan objek setelah itu), tapi saya tidak akan menulis kode seperti itu pada praktek. Saya berpikir bahwa
delete this
akan muncul hanya dalam fungsi yang disebutrelease
atauRelease
dan terlihat seperti:void release() { ref--; if (ref<1) delete this; }
.sumber
Nah, dalam
delete this
konstruksi Component Object Model (COM) dapat menjadi bagian dariRelease
metode yang dipanggil setiap kali Anda ingin melepaskan objek yang didapat:sumber
Ini adalah idiom inti untuk objek yang dihitung referensi.
Penghitungan referensi adalah bentuk yang kuat dari pengumpulan sampah deterministik - ini memastikan objek mengelola masa hidupnya SENDIRI alih-alih mengandalkan petunjuk 'pintar', dll. Untuk melakukannya untuk mereka. Objek yang mendasarinya hanya pernah diakses melalui pointer pintar "Referensi", yang dirancang sedemikian rupa sehingga pointer menambah dan mengurangi bilangan bulat anggota (jumlah referensi) dalam objek yang sebenarnya.
Ketika referensi terakhir turun dari tumpukan atau dihapus, jumlah referensi akan menjadi nol. Perilaku default objek Anda kemudian akan menjadi panggilan untuk "menghapus ini" untuk mengumpulkan sampah - perpustakaan yang saya tulis memberikan panggilan "CountIsZero" virtual yang dilindungi di kelas dasar sehingga Anda dapat menimpa perilaku ini untuk hal-hal seperti caching.
Kunci untuk membuat ini aman adalah tidak memungkinkan pengguna mengakses KONSTRUKTOR objek yang bersangkutan (membuatnya terlindungi), tetapi membuat mereka memanggil beberapa anggota statis - seperti "static Reference CreateT (...)" seperti PABRIK. Dengan begitu Anda TAHU pasti bahwa mereka selalu dibangun dengan "baru" biasa dan bahwa tidak ada pointer mentah yang pernah tersedia, jadi "hapus ini" tidak akan pernah meledak.
sumber
Anda bisa melakukannya. Namun, Anda tidak dapat menetapkan ini. Jadi alasan Anda menyatakan untuk melakukan ini, "Saya ingin mengubah pandangan," tampaknya sangat dipertanyakan. Metode yang lebih baik, menurut saya, adalah untuk objek yang memegang tampilan untuk menggantikan tampilan itu.
Tentu saja, Anda menggunakan objek RAII sehingga Anda tidak perlu memanggil delete sama sekali ... benar?
sumber
Ini adalah pertanyaan lama, dijawab, tetapi @Alexandre bertanya, "Mengapa ada orang yang mau melakukan ini?", Dan saya pikir saya mungkin memberikan contoh penggunaan yang saya pertimbangkan sore ini.
Kode Warisan. Menggunakan pointer telanjang Obj * obj dengan menghapus obj di akhir.
Sayangnya saya kadang-kadang perlu, tidak sering, untuk menjaga objek tetap hidup.
Saya mempertimbangkan untuk menjadikannya sebagai penghitung smart pointer. Tetapi akan ada banyak kode untuk diubah, jika saya harus menggunakannya di
ref_cnt_ptr<Obj>
mana-mana. Dan jika Anda mencampur Obj * dan ref_cnt_ptr telanjang, Anda dapat menghapus objek secara implisit ketika ref_cnt_ptr terakhir hilang, meskipun ada Obj * masih hidup.Jadi saya berpikir untuk membuat eksplisit_delete_ref_cnt_ptr. Yaitu sebuah referensi penghitung referensi di mana penghapusan hanya dilakukan dalam rutinitas penghapusan eksplisit. Menggunakannya di satu tempat di mana kode yang ada mengetahui umur objek, serta dalam kode baru saya yang membuat objek tetap hidup lebih lama.
Menambah dan mengurangi jumlah referensi sebagai eksplisit_delete_ref_cnt_ptr bisa dimanipulasi.
Tapi JANGAN membebaskan ketika jumlah referensi dianggap nol dalam destruktor eksplisit_delete_ref_cnt_ptr.
Hanya membebaskan ketika jumlah referensi dianggap nol dalam operasi penghapusan seperti eksplisit. Misalnya dalam sesuatu seperti:
Oke, kira-kira seperti itu. Agak tidak biasa untuk memiliki referensi tipe pointer yang dihitung tidak secara otomatis menghapus objek yang ditunjuk di destruktor ptr rc'ed. Tapi sepertinya ini mungkin membuat campuran pointer telanjang dan pointer rc sedikit lebih aman.
Namun sejauh ini tidak perlu untuk menghapus ini.
Tapi kemudian terlintas di benak saya: jika objek menunjuk, orang yang dituju, tahu bahwa itu sedang dihitung referensi, misalnya jika jumlah berada di dalam objek (atau dalam beberapa tabel lain), maka delete_if_rc0 rutin bisa menjadi metode dari objek pointee, bukan pointer (pintar).
Sebenarnya, itu tidak perlu menjadi metode anggota sama sekali, tetapi bisa menjadi fungsi bebas:
(BTW, saya tahu kode ini kurang tepat - menjadi kurang dapat dibaca jika saya menambahkan semua detail, jadi saya membiarkannya seperti ini.)
sumber
Hapus ini legal selama objek berada di heap. Anda perlu meminta objek menjadi tumpukan saja. Satu-satunya cara untuk melakukan itu adalah membuat destruktor dilindungi - cara ini bisa saja dihapus HANYA dari kelas, jadi Anda membutuhkan metode yang akan memastikan penghapusan.
sumber