RAII (Resource Acquisition Is Initialization) to idiom C++, który pozwala zarządzać czasem życia zasobów (plików, pamięci, gniazd itp.) poprzez czas życia obiektów. Zasoby są przydzielane w konstruktorze obiektu i zwalniane w destruktorze.
#include <fstream> void save_data(const std::string& filename, const std::string& data) { std::ofstream file(filename); // RAII: plik zamknie się automatycznie if (!file) throw std::runtime_error("Nie można otworzyć pliku"); file << data; } // plik zamknie się tutaj
W przypadku wystąpienia wyjątków destruktor i tak zostanie wywołany, zasoby nie uciekną. Jeśli nie używasz RAII, możesz napotkać na wycieki pamięci i deskryptorów plików.
Czy można zagwarantować brak wycieków pamięci w C++, używając tylko try/catch?
Nie, nie można. Samo użycie try/catch nie gwarantuje zwolnienia zasobów. Gwarancję daje tylko RAII.
int* arr = new int[10]; try { // Praca z arr throw std::runtime_error("Ups"); } catch (...) { // arr nie zwolniono, jeśli nie było delete[] } // arr uciekł!
Historia
W dużym projekcie graficznym regularnie występowały awarie z powodu wyczerpania deskryptorów plików. Okazało się, że pliki były otwierane w funkcji bez owijania w RAII (std::fstream), a przy rzucaniu wyjątków zasoby nie były zwalniane.
Historia
W obsłudze zapytań serwera WWW używano surowej pamięci bez owijania w wskaźnik typu smart – w przypadku rzucenia wyjątku pamięć nie była zwalniana, co prowadziło do degradacji wydajności i awarii.
Historia
W projekcie przetwarzania obrazów tworzone były pliki tymczasowe bez owijania obiektami. Przy rzucaniu wyjątków pliki nie były usuwane, co prowadziło do przepełnienia /tmp na serwerze po kilku miesiącach ciągłej pracy.