Soru hakkında:
C++ başlangıçta performansa odaklanarak tasarlandı, bu nedenle kaynak yönetimi (bellek, dosyalar, akışlar, soketler) genellikle manuel olarak yapılır. Bir istisna durumunda, ele geçirilen kaynakların temizlenmesi gerekir. Stack unwinding (yığın açma), C++'ın bir istisna fırlatma sırasında fonksiyonların düzgün bir şekilde çalışmasını sonlandırmak için kullandığı mekanizmadır.
Problem:
Bir istisna fırlatıldığında kontrol hemen catch bloklarına geçer ve ara fonksiyonlar "açılır": bunların destrüktörleri çağrılır, ancak serbest bırakma fonksiyonlarına açık çağrılar atlanabilir (örneğin, kaynakları otomatik olarak serbest bırakan nesneler kullanılmadığında).
Çözüm:
C++'da kaynak serbest bırakma, serbest bırakma fonksiyonlarını manuel olarak çağırmaktan ziyade destrüktörlere bırakılmalıdır. RAII (Resource Acquisition Is Initialization) şablonu, bir kaynağın serbest bırakılmasını otomatik hale getirmenin kesin bir yoludur. Stack unwinding sırasında, destrüktör çağrılacak ve kaynak, fonksiyondan çıkış yoluna bakılmaksızın serbest bırakılacaktır.
Kod örneği:
#include <fstream> #include <stdexcept> void readFile(const std::string& filename) { std::ifstream file(filename); // İstisna oluşsa bile açılacak ve düzgün bir şekilde kapatılacak if (!file.is_open()) { throw std::runtime_error("Dosya açılamıyor"); } // ... dosyayı okuyoruz } // dosya, istisna olsa bile kapanacak
Anahtar özellikler:
Eğer kodda delete ptr; bir catch bloğunda varsa, bu bellek temizliği için yeterli mi?
Hayır, eğer bellek tahsisinden ve catch bloğundan önce bir istisna fırlatılırsa, bellek temizlenmeyebilir. Daha iyi bir seçenek std::unique_ptr kullanmak veya delete ifadesini destrüktörde yazmaktır.
Kod örneği:
void foo() { int* data = new int[10]; // ... throw std::runtime_error("başarısız"); delete[] data; // istisna anında çağrılmayacak }
Stack unwinding, yığında yerleştirilmiş bir nesnenin destrüktörünü atlayabilir mi?
Hayır, tüm yerel nesneler (istisna fırlatma noktasına kadar yok edilmeyen) oluşturma sırasının tersine yok edilecektir ve destrüktörler garanti edilir.
try bloğundan çıkmak için goto veya longjmp kullanabilir miyiz ve destrüktörlerin çağrılmasını bekleyebilir miyiz?
Hayır. C++ yalnızca bir istisna nedeniyle stack unwinding sırasında destrüktörlerin çağrılmasını garanti eder, hatalı akış kontrolünden (goto, setjmp/longjmp gibi) dolayı değil.
Programcı new ile bellek tahsis eder, istisnaları işlerken bellek serbest bırakmayı catch bloğunda unutuyor, ancak fonksiyondan çıkmanın diğer yollarını göz ardı ediyor.
Artıları:
Eksileri:
Tüm kaynaklar için std::unique_ptr ve RAII sınıfları kullanılıyor, serbest bırakma try/catch'ten bağımsızdır.
Artıları:
Eksileri: