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#include <iostream>2#include <fstream>3using namespace std;45int processFile(const char* filename) {6ifstream file(filename);7if (!file.is_open()) {8throw runtime_error("Dosya açılamadı");9}1011string 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}2223int 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:
1#include <iostream>2#include <fstream>3#include <memory>4using namespace std;56class FileHandler {7private:8ifstream file;9public:10FileHandler(const char* filename) {11file.open(filename);12if (!file.is_open()) {13throw runtime_error("Dosya açılamadı");14}15}1617~FileHandler() {18if (file.is_open()) {19file.close();20}21}2223int 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};3536int 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#include <iostream>2#include <memory>3using namespace std;45class 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};1112int 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 erdiKaynağı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.
0 yorum