C++'da RAII ile Exception-Safe Kaynak Yönetimi

Exception fırlatıldığında açık dosyalar, tahsis edilmiş bellek ve database bağlantıları havada kalabilir. RAII (Resource Acquisition Is Initialization) bu sorunu kök kaynağından çözer: kaynağın yaşam döngüsünü nesnenin yapıcı ve yıkıcısına bağlarsın.

Temel fikir basit: kaynak al yapıcıda, kaynak serbest bırak yıkıcıda. Exception fırlatılsa bile yıkıcı çalışır, kaynak temizlenir.

Bir dosya işleme örneğine bakalım. Eski yöntemde:

1 <iostream>
2 <fstream>
3using namespace std;
4
5int processFile(const char* filename) {
6ifstream file(filename);
7if (!file.is_open()) {
8throw runtime_error("Dosya açılamadı");
9}
10
11string line;
12int count = 0;
13while (getline(file, line)) {
14if (line.empty()) {
15throw runtime_error("Boş satır bulundu"); // File açık kaldı!
16}
17count++;
18}
19file.close();
20return count;
21}
22
23int main() {
24try {
25int result = processFile("data.txt");
26cout << "Satır sayısı: " << result << endl;
27} catch (const exception& e) {
28cerr << "Hata: " << e.what() << endl;
29}
30return 0;
31}

Exception fırlatıldığında `file.close()` hiç çalışmaz. Dosya kaynağı sızar.

RAAI ile çözelim:

Reklam · TEST
AdSense Test ReklamıYazı arası (gönderi içi) · Yazı arası
1 <iostream>
2 <fstream>
3 <memory>
4using namespace std;
5
6class FileHandler {
7private:
8ifstream file;
9public:
10FileHandler(const char* filename) {
11file.open(filename);
12if (!file.is_open()) {
13throw runtime_error("Dosya açılamadı");
14}
15}
16
17~FileHandler() {
18if (file.is_open()) {
19file.close();
20}
21}
22
23int countLines() {
24string line;
25int count = 0;
26while (getline(file, line)) {
27if (line.empty()) {
28throw runtime_error("Boş satır bulundu");
29}
30count++;
31}
32return count;
33}
34};
35
36int main() {
37try {
38FileHandler handler("data.txt");
39cout << "Satır sayısı: " << handler.countLines() << endl;
40} catch (const exception& e) {
41cerr << "Hata: " << e.what() << endl;
42}
43return 0;
44}

Fark şu: `handler` nesnesi scope'tan çıkınca (exception olsa bile) yıkıcı otomatik çalışır, dosya kapanır. Hiç sızıntı yok.

C++11+ ile `unique_ptr` ve `shared_ptr` de RAII ilkesini uygular:

1 <iostream>
2 <memory>
3using namespace std;
4
5class Database {
6public:
7Database() { cout << "Bağlantı açıldı" << endl; }
8~Database() { cout << "Bağlantı kapatıldı" << endl; }
9void query() { cout << "Sorgu çalıştırıldı" << endl; }
10};
11
12int main() {
13try {
14unique_ptr<Database> db(new Database());
15db->query();
16throw runtime_error("Sorgu hatası");
17} catch (const exception& e) {
18cerr << "Hata: " << e.what() << endl;
19}
20cout << "Program sona erdi" << endl;
21return 0;
22}

Beklenen çıktı:

1Bağlantı açıldı
2Sorgu çalıştırıldı
3Hata: Sorgu hatası
4Bağlantı kapatıldı
5Program sona erdi

Kaynağın kapatılması exception'dan sonra da gerçekleşti. Sık hata: yıkıcıda exception fırlatmak. Yıkıcılar `noexcept` olmalı, aksi durumda program terminate olur.

Reklam · TEST
AdSense Test ReklamıGönderi altı · Görüntülü
konu hakkında tepkinizi verebilirsiniz