Apa itu RAII? Contohnya?


19

Selalu ketika istilah RAII digunakan, orang sebenarnya berbicara tentang dekonstruksi daripada inisialisasi. Saya pikir saya memiliki pemahaman dasar apa artinya tapi saya tidak yakin. Juga: apakah C ++ satu-satunya bahasa RAII? Bagaimana dengan Java atau C # /. NET?

Jawaban:


25

Akuisisi Sumber Daya Adalah Inisialisasi berarti bahwa objek harus menjaga diri mereka sebagai paket lengkap dan tidak mengharapkan kode lain untuk memberi contoh "hei omong-omong, Anda akan segera dibersihkan - tolong bereskan sekarang." Biasanya ini berarti ada sesuatu yang bermakna dalam destruktor. Ini juga berarti Anda menulis kelas khusus untuk mengelola sumber daya, mengetahui bahwa dalam keadaan tertentu yang sulit diprediksi, seperti pengecualian yang dilemparkan, Anda dapat mengandalkan penghancur yang mengeksekusi.

Katakanlah Anda ingin menulis beberapa kode di mana Anda akan mengubah kursor windows menjadi kursor tunggu (jam pasir, donat tidak berfungsi, dll), lakukan hal-hal Anda, dan kemudian ubah kembali. Dan katakan juga bahwa "kerjakan barangmu" mungkin memberikan pengecualian. Cara RAII melakukan itu adalah membuat kelas yang ctornya mengatur kursor untuk menunggu, yang satu-satunya "nyata" metode melakukan apa pun yang Anda inginkan dilakukan, dan yang dtor mengatur kursor kembali. Sumber daya (dalam hal ini kondisi kursor) terikat ke ruang lingkup suatu objek. Ketika Anda memperoleh sumber daya Anda menginisialisasi objek. Anda dapat mengandalkan objek yang akan dihancurkan jika pengecualian dilemparkan, dan itu berarti Anda dapat mengandalkan untuk membersihkan sumber daya.

Menggunakan RAII dengan baik berarti Anda tidak perlu finally. Tentu saja, ini bergantung pada kehancuran deterministik, yang tidak dapat Anda miliki di Jawa. Anda bisa mendapatkan semacam penghancuran deterministik dalam C # dan VB.NET dengan using.


4
Saya pikir ini yang Anda maksud, tetapi Anda mungkin ingin menambahkan bahwa alasan mengapa Java dan C # tidak mendukung RAII adalah karena pengumpul sampah. Dalam C ++, objek lokal akan dihancurkan segera setelah keluar dari ruang lingkup. Di Java / C # ini tidak benar.
Jason Baker

Memperluas pada titik Jason, alasan mengapa Java dan C # tidak dapat menjamin kehancuran tepat waktu adalah karena kemungkinan siklus referensi, yang berarti tidak mungkin untuk menentukan urutan aman untuk menjalankan destruktor. Referensi siklus juga dapat terjadi di C ++, tetapi implikasinya berbeda - programmer menjadi bertanggung jawab untuk menentukan urutan kehancuran dan melakukan penghapusan eksplisit. Tanggung jawab itu sangat sering dikemas dalam beberapa destruktor kelas-tingkat yang lebih tinggi - misalnya kelas kontainer bertanggung jawab untuk memastikan semua item yang terkandung hancur. "Kepemilikan" adalah kuncinya.
Steve314

1
@ Alasan itulah yang saya maksud dengan "kehancuran deterministik" - seorang programmer C ++ tahu kapan destruktor akan berjalan.
Kate Gregory

Saya tahu ini adalah jawaban lama, tapi saya masih agak bingung. Saya baru belajar istilah dan beberapa info mengatakan bahwa akuisisi harus terjadi di konstruktor. Itu tidak masuk akal bagi saya dan jawaban ini tampaknya bertentangan, tetapi bisakah Anda mengklarifikasi?
Per Johansson

1
@ PerJohansson Ya, Anda memperoleh di ctor. Dan Anda lepaskan di dtor. Saya fokus pada poin kedua, tetapi mereka pergi bersama. Setelah ctor selesai, Anda tahu Anda memiliki objek yang valid. Dan Anda tahu bahwa apa pun yang terjadi, sumber daya akan dilepaskan pada waktu yang tepat.
Kate Gregory

4

RAII sebagian tentang memutuskan kapan suatu objek menjadi bertanggung jawab atas pembersihannya sendiri - aturannya adalah bahwa objek menjadi bertanggung jawab jika dan ketika inisialisasi konstruktornya selesai. Simetri inisialisasi dan pembersihan, konstruktor dan destruktor, berarti keduanya memiliki ikatan yang erat satu sama lain.

Satu poin dari RAII adalah untuk memastikan keamanan pengecualian - bahwa aplikasi tetap konsisten saat pengecualian dilemparkan. Pada pandangan pertama ini sepele - ketika pengecualian menyebabkan ruang lingkup untuk keluar, variabel lokal dalam ruang lingkup itu perlu dihancurkan.

Tetapi apa yang terjadi jika lemparan eksepsi terjadi di dalam konstruktor?

Nah, objek belum sepenuhnya dibangun, jadi tidak bisa dihancurkan dengan aman. Konstruktor harus memiliki blok percobaan yang diperlukan untuk memastikan bahwa pembersihan yang diperlukan dilakukan sebelum pengecualian dilakukan. Setelah pengecualian berpropagasi di luar ruang lingkup di mana objek dibangun, tidak akan ada panggilan destruktor, karena objek tidak dibangun di tempat pertama.

Pertimbangkan secara khusus konstruktor untuk data anggota di dalam objek yang dihancurkan. Jika salah satu dari itu melempar pengecualian, kode konstruktor utama Anda tidak akan berjalan sama sekali - tetapi beberapa kode yang membentuk bagian implisit dari konstruktor itu akan miliki. Setiap anggota yang telah berhasil dibangun akan secara otomatis dihancurkan. Setiap anggota yang tidak dibangun (termasuk yang melempar pengecualian) tidak.

Jadi pada dasarnya, RAII adalah kebijakan yang memastikan bahwa segala sesuatu yang dibangun sepenuhnya akan dihancurkan tepat waktu, terutama di hadapan lemparan pengecualian, dan bahwa objek apa pun dapat dibangun sepenuhnya atau tidak (tidak ada setengah membangun objek yang Anda tidak bisa tahu cara membersihkan dengan aman). Sumber daya yang dialokasikan juga dibebaskan. Dan banyak pekerjaan yang dilakukan secara otomatis, sehingga programmer tidak perlu terlalu khawatir tentang hal itu.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.