RAII sebagai Pola
Termasuk bagian Pemrograman Berorientasi Object dalam perjalanan C++ di Coddy. Pelajaran 102 dari 104.
RAII (Resource Acquisition Is Initialization) bukan sekadar idiom C++, tetapi pola desain yang ampuh dan mengaitkan pengelolaan sumber daya dengan masa hidup object. Kamu sudah melihat RAII pada smart pointer, tetapi pola ini berlaku untuk sumber daya apa pun: file handle, koneksi jaringan, mutex, atau transaksi database.
Gagasan utamanya sederhana: dapatkan sumber daya di constructor, lepaskan di destructor. Karena C++ menjamin destructor dijalankan saat object keluar dari cakupan, pembersihan terjadi secara otomatis, bahkan saat exception terjadi:
#include <iostream>
#include <fstream>
class FileGuard {
std::ofstream file;
public:
FileGuard(const std::string& filename) : file(filename) {
if (!file.is_open()) {
std::cout << "Failed to open file\n";
}
}
void write(const std::string& text) {
if (file.is_open()) file << text;
}
~FileGuard() {
if (file.is_open()) {
file.close();
std::cout << "File closed automatically\n";
}
}
};
int main() {
{
FileGuard guard("output.txt");
guard.write("Hello RAII");
} // Destructor dipanggil di sini, file ditutup
std::cout << "After scope\n";
}RAII sangat berguna saat mengelola lock dalam kode multithread. std::lock_guard dari library standar mengikuti pola ini: objek ini memperoleh mutex saat konstruksi dan melepasnya saat destruksi, sehingga mencegah deadlock akibat lupa melepas lock.
Saat mengimplementasikan class RAII, ingat untuk menghapus atau mengimplementasikan operasi penyalinan/pemindahan dengan benar (Rule of Five) agar tidak terjadi duplikasi resource atau resource dilepas dua kali. RAII mengubah pengelolaan resource manual yang rentan kesalahan menjadi pembersihan otomatis yang aman.
Tantangan
MudahMari buat Connection Pool Manager menggunakan RAII untuk mengelola koneksi database dengan aman. Dalam aplikasi nyata, koneksi database adalah sumber daya yang mahal dan harus diperoleh serta dilepaskan dengan benar. Kamu akan membuat pembungkus RAII yang menjamin koneksi selalu dikembalikan ke pool, bahkan jika terjadi exception atau jalur kode menjadi rumit.
Kamu akan mengatur kodemu dalam tiga file:
ConnectionPool.h: Buat pool koneksi sederhana yang mengelola jumlah koneksi terbatas.Class
ConnectionPoolharus melacak jumlah koneksi yang tersedia, dimulai dari kapasitas yang diberikan ke constructor. Implementasikan:acquire(): jika koneksi tersedia, kurangi jumlahnya dan tampilkanConnection acquired (X available), dengan X sebagai jumlah yang tersisa; kembalikantruejika berhasil, ataufalsejika tidak ada koneksi yang tersediarelease(): tambah jumlah koneksi yang tersedia dan tampilkanConnection released (X available)available(): mengembalikan jumlah koneksi yang tersedia saat ini
ConnectionGuard.h: Buat pembungkus RAII yang mengelola satu koneksi dengan aman.Class
ConnectionGuardmenerapkan pola RAII. Class ini harus:- Menerima referensi ke
ConnectionPooldi constructornya dan mencoba memperoleh koneksi - Menyimpan informasi apakah upaya memperoleh koneksi berhasil
- Menyediakan method
isConnected()untuk memeriksa apakah guard memegang koneksi yang valid - Secara otomatis mengembalikan koneksi ke pool di destructor, hanya jika koneksi berhasil diperoleh
- Menghapus copy constructor dan copy assignment untuk mencegah duplikasi sumber daya (pertimbangan Rule of Five)
Saat destructor berjalan, jika koneksi sedang dipegang, tampilkan
Guard releasing connectionsebelum memanggil release pada pool.- Menerima referensi ke
main.cpp: Tunjukkan pembersihan otomatis RAII melalui scope.Baca dua input:
- Kapasitas pool (integer)
- Jumlah koneksi yang diminta (integer)
Buat
ConnectionPooldengan kapasitas yang diberikan. Kemudian, di dalam scope bertingkat (menggunakan kurung kurawal), buat sejumlah objectConnectionGuardyang diminta dan simpan dalam vector. Untuk setiap guard, tampilkan apakah koneksi berhasil diperoleh:- Jika koneksi berhasil:
Guard N: Connected - Jika koneksi tidak berhasil:
Guard N: Failed to connect
dengan N dimulai dari 1
Setelah scope berakhir dan guard dihancurkan, tampilkan
After scope: X connections availableuntuk menunjukkan kondisi akhir pool.
Contohnya, dengan input 2 dan 3:
Connection acquired (1 available)
Guard 1: Connected
Connection acquired (0 available)
Guard 2: Connected
Guard 3: Failed to connect
Guard releasing connection
Connection released (1 available)
Guard releasing connection
Connection released (2 available)
After scope: 2 connections availableDengan input 3 dan 2:
Connection acquired (2 available)
Guard 1: Connected
Connection acquired (1 available)
Guard 2: Connected
Guard releasing connection
Connection released (2 available)
Guard releasing connection
Connection released (3 available)
After scope: 3 connections availablePerhatikan bahwa koneksi dilepaskan secara otomatis saat guard keluar dari scope. Kamu tidak pernah memanggil release secara eksplisit di kodemu pada main. Destructor berjalan dalam urutan terbalik dari konstruksi, guard terakhir dihancurkan lebih dulu, dan setiap koneksi yang berhasil diperoleh dijamin akan dikembalikan. Inilah keunggulan RAII: pembersihan sumber daya berlangsung secara otomatis dan andal, apa pun cara scope berakhir.
Coba sendiri
#include <iostream>
#include <vector>
#include "ConnectionPool.h"
#include "ConnectionGuard.h"
using namespace std;
int main() {
// Baca input
int capacity;
int numConnections;
cin >> capacity;
cin >> numConnections;
// TODO: Buat ConnectionPool dengan kapasitas yang diberikan
// TODO: Buat cakupan bertingkat menggunakan kurung kurawal
{
// TODO: Buat vector untuk menyimpan object ConnectionGuard
// Petunjuk: Kamu perlu menggunakan pointer atau smart pointer karena ConnectionGuard
// memiliki copy constructor yang dihapus
// TODO: Gunakan perulangan untuk membuat numConnections guard
// Untuk setiap guard, cetak salah satu dari:
// "Guard N: Connected" atau "Guard N: Failed to connect"
// dengan N dimulai dari 1
}
// Guard dihancurkan di sini saat cakupan berakhir
// TODO: Cetak "After scope: X connections available"
return 0;
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Object
1Dasar-Dasar OOP
File EksternalBuild dan Kompilasi C++File Header dan File SourceNamespace dan CakupanPengantar OOP dalam C++class vs objectPointer 'this'method (Fungsi Anggota)Atribut (Anggota Data)Dasar Ctor dan DtorRingkasan: Kalkulator Sederhana4Properti class
Anggota instance vs staticGetter dan setterFungsi anggota constKata kunci mutableMethod dan variabel staticFungsi dan class friendRangkuman, Pengelola Rekening Bank7Pewarisan
Pewarisan DasarTingkat Akses pada PewarisanUrutan Pemanggilan Ctor & DtorPenimpaan methodFungsi Virtual & VTablePewarisan BergandaPewarisan VirtualRangkuman: Hierarki Karyawan2Manajemen Memori
Memori Stack vs HeapPointer dan ReferenceMemori Dinamis (new/delete)Smart Pointer di C++RAII di C++Rangkuman: Pengelola Array Dinamis5Enkapsulasi
Penentu Akses dalam C++Penentu Akses secara MendalamPenyembunyian Informasistruct vs classNested dan Inner classRangkuman, Sistem Catatan Siswa8Polimorfisme
Polimorfisme saat Compile vs RuntimeOverloading FungsiMeninjau Kembali Fungsi VirtualFungsi Virtual MurniKelas AbstrakDesain Interface di C++Casting Dinamis & RTTIRangkuman: Kalkulator Bentuk11Konsep OOP Lanjutan
Komposisi vs PewarisanMixin melalui CRTPIdiom PimplPenghapusan TipeKelas Enum dan Pengetikan KuatPenanganan Pengecualian dalam OOPHierarki Pengecualian Kustom14Pola Desain Bagian 2
Pola CommandPola AdapterPola DecoratorPola Template MethodPola StatePola CompositeRAII sebagai Pola3Konstruktor & Destruktor
Konstruktor DefaultKonstruktor BerparameterKonstruktor SalinKonstruktor PindahDaftar Inisialisasi KonstruktorKonstruktor DelegasiKupas Tuntas DestruktorAturan Tiga, Lima, dan NolRangkuman: class String6Overloading Operator
Pengantar Overloading OperatorOverloading Operator AritmetikaOverloading Operator PerbandinganOperator StreamOverloading Operator PenugasanOverloading Operator [] dan ()Operator Konversi TipeRingkasan, class Matrix9Template
Template FungsiTemplate classSpesialisasi TemplateTemplate VariadikDasar SFINAE & Type TraitsRangkuman, Container GenerikLatihan sendiri: Compiler C++ online