Ada jawaban yang sangat bagus di luar sana, jadi saya hanya menambahkan beberapa hal yang terlupakan.
0. RAII adalah tentang ruang lingkup
RAII adalah tentang keduanya:
- memperoleh sumber daya (tidak peduli sumber daya apa) di konstruktor, dan membatalkan memperolehnya di destruktor.
- membuat konstruktor dieksekusi ketika variabel dideklarasikan, dan destruktor secara otomatis dieksekusi ketika variabel keluar dari ruang lingkup.
Yang lain sudah menjawab tentang itu, jadi saya tidak akan menjelaskannya.
1. Saat melakukan coding di Java atau C #, Anda sudah menggunakan RAII ...
MONSIEUR JOURDAIN: Apa! Ketika saya berkata, "Nicole, bawakan sandal saya, dan berikan saya minuman malam saya," itu prosa?
FILOSOFI MASTER: Ya, Pak.
MONSIEUR JOURDAIN: Selama lebih dari empat puluh tahun saya telah berbicara prosa tanpa mengetahui apa pun tentangnya, dan saya sangat berterima kasih kepada Anda karena telah mengajari saya hal itu.
- Molière: Pria Kelas Menengah, Babak 2, Adegan 4
Seperti yang dilakukan Monsieur Jourdain dengan prosa, C # dan bahkan orang Java sudah menggunakan RAII, tetapi dengan cara tersembunyi. Misalnya, kode Java berikut (yang ditulis dengan cara yang sama di C # dengan menggantinya synchronized
dengan lock
):
void foo()
{
// etc.
synchronized(someObject)
{
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
... sudah menggunakan RAII: Akuisisi mutex dilakukan di kata kunci ( synchronized
atau lock
), dan pembatalan akuisisi akan dilakukan saat keluar dari cakupan.
Sangat alami dalam notasinya sehingga hampir tidak memerlukan penjelasan bahkan bagi orang yang belum pernah mendengar tentang RAII.
Keunggulan C ++ dibandingkan Java dan C # di sini adalah bahwa apa pun dapat dibuat menggunakan RAII. Misalnya, tidak ada build-in langsung yang setara dengan synchronized
nor lock
di C ++, tetapi kita masih bisa memilikinya.
Di C ++, itu akan ditulis:
void foo()
{
// etc.
{
Lock lock(someObject) ; // lock is an object of type Lock whose
// constructor acquires a mutex on
// someObject and whose destructor will
// un-acquire it
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
yang dapat dengan mudah ditulis dengan cara Java / C # (menggunakan makro C ++):
void foo()
{
// etc.
LOCK(someObject)
{
// if something throws here, the lock on someObject will
// be unlocked
}
// etc.
}
2. RAII memiliki kegunaan alternatif
WHITE RABBIT: [bernyanyi] Saya terlambat / Saya terlambat / Untuk kencan yang sangat penting. / Tidak ada waktu untuk mengatakan "Halo." / Selamat tinggal. / Saya terlambat, saya terlambat, saya terlambat.
- Alice in Wonderland (versi Disney, 1951)
Anda tahu kapan konstruktor akan dipanggil (di deklarasi objek), dan Anda tahu kapan destruktor yang sesuai akan dipanggil (di pintu keluar cakupan), sehingga Anda dapat menulis kode yang hampir ajaib dengan hanya satu baris. Selamat datang di negeri ajaib C ++ (setidaknya, dari sudut pandang pengembang C ++).
Misalnya, Anda dapat menulis objek counter (saya biarkan sebagai latihan) dan menggunakannya hanya dengan mendeklarasikan variabelnya, seperti objek kunci di atas digunakan:
void foo()
{
double timeElapsed = 0 ;
{
Counter counter(timeElapsed) ;
// do something lengthy
}
// now, the timeElapsed variable contain the time elapsed
// from the Counter's declaration till the scope exit
}
yang tentu saja, dapat ditulis, sekali lagi, cara Java / C # menggunakan makro:
void foo()
{
double timeElapsed = 0 ;
COUNTER(timeElapsed)
{
// do something lengthy
}
// now, the timeElapsed variable contain the time elapsed
// from the Counter's declaration till the scope exit
}
3. Mengapa C ++ kurang finally
?
[BERTERIAK] Ini hitungan mundur terakhir !
- Eropa: The Final Countdown (maaf, saya kehabisan kutipan, di sini ... :-)
The finally
klausul digunakan dalam C # / Java untuk menangani pembuangan sumber daya dalam kasus lingkup keluar (baik melalui return
atau pengecualian dilemparkan).
Pembaca spesifikasi yang cerdik akan menyadari bahwa C ++ tidak memiliki klausa akhirnya. Dan ini bukan kesalahan, karena C ++ tidak membutuhkannya, karena RAII sudah menangani pembuangan sumber daya. (Dan percayalah, menulis destruktor C ++ jauh lebih mudah daripada menulis klausa akhir Java yang benar, atau bahkan metode Buang C # yang benar).
Meski begitu, terkadang, finally
klausul akan tetap keren. Bisakah kita melakukannya di C ++? Ya kita bisa! Dan lagi dengan penggunaan RAII secara bergantian.
Kesimpulan: RAII lebih dari sekedar filosofi dalam C ++: Ini C ++
RAII? INI ADALAH C ++ !!!
- Komentar marah pengembang C ++, tanpa malu-malu disalin oleh raja Sparta yang tidak dikenal dan 300 temannya
Ketika Anda mencapai beberapa tingkat pengalaman dalam C ++, Anda mulai berpikir dalam istilah RAII , dalam istilah eksekusi otomatis konstruktor dan destruktor .
Anda mulai berpikir dalam lingkup cakupan , {
dan }
karakter dan menjadi salah satu yang paling penting dalam kode Anda.
Dan hampir semuanya cocok dalam hal RAII: pengecualian keamanan, mutex, koneksi database, permintaan database, koneksi server, jam, pegangan OS, dll., Dan terakhir, namun tidak kalah pentingnya, memori.
Bagian database tidak dapat diabaikan, karena, jika Anda menerima pembayaran, Anda bahkan dapat menulis dalam gaya " pemrograman transaksional ", mengeksekusi baris dan baris kode sampai memutuskan, pada akhirnya, jika Anda ingin melakukan semua perubahan , atau, jika tidak memungkinkan, mengembalikan semua perubahan (selama setiap baris memenuhi setidaknya Jaminan Pengecualian Kuat). (lihat bagian kedua dari artikel Herb's Sutter ini untuk pemrograman transaksional).
Dan seperti teka-teki, semuanya cocok.
RAII adalah bagian dari C ++, C ++ tidak bisa menjadi C ++ tanpanya.
Ini menjelaskan mengapa developer C ++ berpengalaman begitu terpikat dengan RAII, dan mengapa RAII menjadi hal pertama yang mereka telusuri saat mencoba bahasa lain.
Dan ini menjelaskan mengapa Pengumpul Sampah, meskipun merupakan bagian dari teknologi yang luar biasa, tidak begitu mengesankan dari sudut pandang pengembang C ++:
- RAII sudah menangani sebagian besar kasus yang ditangani oleh GC
- GC menangani lebih baik daripada RAII dengan referensi melingkar pada objek terkelola murni (dimitigasi dengan penggunaan cerdas pointer lemah)
- Tetap A GC terbatas pada memori, sementara RAII dapat menangani semua jenis sumber daya.
- Seperti dijelaskan di atas, RAII dapat melakukan lebih banyak lagi ...