Yang dimaksud dengan Akuisisi Sumber Daya adalah Inisialisasi (RAII)?
Yang dimaksud dengan Akuisisi Sumber Daya adalah Inisialisasi (RAII)?
Jawaban:
Ini adalah nama yang sangat mengerikan untuk konsep yang sangat kuat, dan mungkin salah satu hal nomor 1 yang dilewatkan oleh pengembang C ++ ketika mereka beralih ke bahasa lain. Ada sedikit gerakan untuk mencoba mengubah nama konsep ini sebagai Manajemen Sumber Daya Lingkup-Bound , meskipun tampaknya belum berhasil.
Ketika kita mengatakan 'Sumber Daya' kita tidak hanya berarti memori - itu bisa berupa pegangan file, soket jaringan, pegangan basis data, objek GDI ... Singkatnya, hal-hal yang memiliki persediaan terbatas dan oleh karena itu kita harus dapat kendalikan penggunaannya. Aspek 'Lingkup-terikat' berarti bahwa masa objek terikat pada ruang lingkup variabel, jadi ketika variabel keluar dari ruang lingkup maka destruktor akan melepaskan sumber daya. Properti yang sangat berguna dari ini adalah membuat pengecualian keamanan yang lebih besar. Sebagai contoh, bandingkan ini:
RawResourceHandle* handle=createNewResource();
handle->performInvalidOperation(); // Oops, throws exception
...
deleteResource(handle); // oh dear, never gets called so the resource leaks
Dengan RAII
class ManagedResourceHandle {
public:
ManagedResourceHandle(RawResourceHandle* rawHandle_) : rawHandle(rawHandle_) {};
~ManagedResourceHandle() {delete rawHandle; }
... // omitted operator*, etc
private:
RawResourceHandle* rawHandle;
};
ManagedResourceHandle handle(createNewResource());
handle->performInvalidOperation();
Dalam kasus yang terakhir ini, ketika pengecualian dilemparkan dan tumpukan dibatalkan, variabel lokal dihancurkan yang memastikan bahwa sumber daya kita dibersihkan dan tidak bocor.
Scope-Bound
pilihan nama terbaik di sini karena penspesifikasi kelas penyimpanan bersama dengan ruang lingkup menentukan durasi penyimpanan suatu entitas. Mempersempit batasan ruang lingkup mungkin merupakan penyederhanaan yang berguna, namun tidak 100% tepat
Ini adalah idiom pemrograman yang secara singkat berarti bahwa Anda
Ini menjamin bahwa apa pun yang terjadi ketika sumber daya sedang digunakan, pada akhirnya akan dibebaskan (apakah karena pengembalian normal, penghancuran objek yang mengandung, atau pengecualian yang dilemparkan).
Ini adalah praktik yang baik digunakan secara luas dalam C ++, karena selain sebagai cara yang aman untuk menangani sumber daya, ini juga membuat kode Anda jauh lebih bersih karena Anda tidak perlu mencampur kode penanganan kesalahan dengan fungsi utama.
*
Pembaruan: "lokal" dapat berarti variabel lokal, atau variabel anggota tidak statis dari suatu kelas. Dalam kasus terakhir variabel anggota diinisialisasi dan dihancurkan dengan objek pemiliknya.
**
Update2: seperti yang ditunjukkan oleh @sbi, sumber daya - meskipun sering dialokasikan di dalam konstruktor - juga dapat dialokasikan di luar dan diteruskan sebagai parameter.
open()
/ close()
metode untuk menginisialisasi dan melepaskan sumber daya, hanya konstruktor dan destruktor, sehingga 'memegang' sumber daya hanya seumur hidup objek, tidak peduli apakah itu seumur hidup adalah ditangani oleh konteks (tumpukan) atau secara eksplisit (alokasi dinamis)
"RAII" adalah singkatan dari "Akuisisi Sumber Daya adalah Inisialisasi" dan sebenarnya cukup keliru, karena ini bukan akuisisi sumber daya (dan inisialisasi objek) yang bersangkutan, tetapi melepaskan sumber daya (dengan cara penghancuran objek) ).
Tapi RAII adalah nama yang kita dapat dan tongkat itu.
Pada intinya, idiom ini menampilkan sumber daya enkapsulasi (potongan memori, file terbuka, mutex yang tidak terkunci, Anda-nama-itu) di objek lokal, otomatis , dan memiliki penghancur objek yang melepaskan sumber daya ketika objek dihancurkan di akhir dari ruang lingkup miliknya:
{
raii obj(acquire_resource());
// ...
} // obj's dtor will call release_resource()
Tentu saja, objek tidak selalu objek lokal, otomatis. Mereka juga bisa menjadi anggota kelas:
class something {
private:
raii obj_; // will live and die with instances of the class
// ...
};
Jika objek tersebut mengelola memori, mereka sering disebut "smart pointer".
Ada banyak variasi dari ini. Misalnya, dalam cuplikan kode pertama, muncul pertanyaan apa yang akan terjadi jika seseorang ingin menyalin obj
. Cara termudah adalah dengan tidak mengizinkan penyalinan. std::unique_ptr<>
, penunjuk pintar untuk menjadi bagian dari pustaka standar seperti yang ditampilkan oleh standar C ++ berikutnya, melakukan hal ini.
Penunjuk pintar lainnya, std::shared_ptr
fitur "kepemilikan bersama" dari sumber daya (objek yang dialokasikan secara dinamis) yang dimilikinya. Artinya, itu dapat dengan bebas disalin dan semua salinan merujuk ke objek yang sama. Pointer pintar melacak berapa banyak salinan merujuk ke objek yang sama dan akan menghapusnya ketika yang terakhir sedang dihancurkan.
Varian ketiga ditampilkan olehstd::auto_ptr
yang mengimplementasikan semacam semantik bergerak: Suatu objek hanya dimiliki oleh satu pointer, dan upaya untuk menyalin objek akan menghasilkan (melalui peretasan sintaksis) dalam mentransfer kepemilikan objek ke target operasi penyalinan.
std::auto_ptr
adalah versi usang dari std::unique_ptr
. std::auto_ptr
jenis semantik langkah disimulasikan sebanyak mungkin dalam C ++ 98, std::unique_ptr
menggunakan semantik langkah baru C ++ 11. Kelas baru dibuat karena semantik langkah C ++ 11 lebih eksplisit (memerlukan std::move
kecuali dari sementara) sementara itu default untuk setiap salinan dari non-const di std::auto_ptr
.
Seumur hidup suatu objek ditentukan oleh cakupannya. Namun, terkadang kita perlu, atau berguna, untuk membuat objek yang hidup secara independen dari ruang lingkup di mana ia dibuat. Dalam C ++, operator new
digunakan untuk membuat objek seperti itu. Dan untuk menghancurkan objek, operator delete
dapat digunakan. Objek yang dibuat oleh operator new
dialokasikan secara dinamis, yaitu dialokasikan dalam memori dinamis (juga disebut heap atau free store ). Jadi, objek yang dibuat oleh new
akan terus ada sampai secara eksplisit dihancurkan menggunakan delete
.
Beberapa kesalahan yang dapat terjadi saat menggunakan new
dan delete
adalah:
new
untuk mengalokasikan objek dan lupa delete
objek.delete
objek, dan kemudian menggunakan pointer lainnya.delete
objek dua kali.Secara umum, variabel cakupan lebih disukai. Namun, RAII dapat digunakan sebagai alternatif new
dan delete
untuk membuat objek hidup secara independen dari ruang lingkupnya. Teknik semacam itu terdiri dari mengambil pointer ke objek yang dialokasikan pada heap dan menempatkannya di objek handle / manager . Yang terakhir memiliki destruktor yang akan mengurus penghancuran objek. Ini akan menjamin bahwa objek tersedia untuk fungsi apa pun yang ingin mengaksesnya, dan bahwa objek dihancurkan ketika masa pakai objek pegangan berakhir, tanpa perlu pembersihan eksplisit.
Contoh dari pustaka standar C ++ yang menggunakan RAII adalah std::string
dan std::vector
.
Pertimbangkan potongan kode ini:
void fn(const std::string& str)
{
std::vector<char> vec;
for (auto c : str)
vec.push_back(c);
// do something
}
ketika Anda membuat vektor dan Anda mendorong elemen ke sana, Anda tidak peduli tentang mengalokasikan dan membatalkan alokasi elemen tersebut. Vektor digunakan new
untuk mengalokasikan ruang untuk elemen-elemennya di heap, dan delete
untuk membebaskan ruang itu. Anda sebagai pengguna vektor, Anda tidak peduli tentang detail implementasi dan akan mempercayai vektor untuk tidak bocor. Dalam hal ini, vektor adalah objek pegangan dari elemen-elemennya.
Contoh lain dari perpustakaan standar yang digunakan RAII adalah std::shared_ptr
, std::unique_ptr
, dan std::lock_guard
.
Nama lain untuk teknik ini adalah SBRM , kependekan dari Scope-Bound Resource Management .
Buku C ++ Pemrograman dengan Pola Desain Terungkap menggambarkan RAII sebagai:
Dimana
Sumberdaya diimplementasikan sebagai kelas, dan semua pointer memiliki pembungkus kelas di sekitar mereka (menjadikannya pointer cerdas).
Sumber daya diperoleh dengan memanggil konstruktor mereka dan dirilis secara implisit (dalam urutan terbalik dari perolehan) dengan memanggil destruktor mereka.
Ada tiga bagian untuk kelas RAII:
RAII singkatan dari "Akuisisi Sumber Daya adalah inisialisasi." Bagian "akuisisi sumber daya" dari RAII adalah tempat Anda memulai sesuatu yang harus diakhiri nanti, seperti:
Bagian "is inisialisasi" berarti bahwa akuisisi terjadi di dalam konstruktor kelas.
https://www.tomdalling.com/blog/software-design/resource-acquis-is-initialisation-raii-explained/
Manajemen memori manual adalah mimpi buruk yang programmer temukan cara untuk menghindari sejak penemuan kompiler. Memprogram bahasa dengan pemulung membuat hidup lebih mudah, tetapi dengan mengorbankan kinerja. Dalam artikel ini - Menghilangkan Pengumpul Sampah: Cara RAII , insinyur Toptal Peter Goodspeed-Niklaus memberi kita mengintip sejarah pemulung dan menjelaskan bagaimana pengertian kepemilikan dan pinjaman dapat membantu menghilangkan pengumpul sampah tanpa mengorbankan jaminan keselamatan mereka.