RAII w C++
Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 16 z 104.
RAII (Resource Acquisition Is Initialization) to podstawowy idiom C++, w którym zarządzanie zasobami jest powiązane z czasem życia obiektu. Pomysł jest prosty: pozyskuj zasoby w konstruktorze, zwalniaj je w destruktorze.
Gdy obiekt zostaje utworzony, uzyskuje wszystkie potrzebne mu zasoby. Gdy obiekt wychodzi poza zakres, jego destruktor automatycznie zwalnia te zasoby. Gwarantuje to sprzątanie nawet w przypadku wystąpienia wyjątków.
class FileHandler {
std::FILE* file;
public:
FileHandler(const char* filename) {
file = std::fopen(filename, "r"); // Pozyskaj zasób
}
~FileHandler() {
if (file) std::fclose(file); // Zwolnij zasób
}
};Dzięki RAII nigdy nie zapomnisz o sprzątaniu:
void processFile() {
FileHandler handler("data.txt"); // Zasób został pozyskany
// Praca z plikiem...
// Jeśli tutaj zostanie zgłoszony wyjątek, destruktor i tak zostanie wywołany!
} // Zasób zostaje automatycznie zwolnionyInteligentne wskaźniki są doskonałym przykładem RAII w praktyce. unique_ptr przejmuje własność pamięci sterty w konstruktorze i usuwa ją w destruktorze. Korzystasz już z RAII, nawet o tym nie wiedząc!
RAII ma zastosowanie do dowolnych zasobów: pamięci, uchwytów plików, połączeń sieciowych, muteksów lub połączeń z bazą danych. Opakowując zasoby w obiekty, C++ zapewnia deterministyczne sprzątanie i eliminuje całe kategorie błędów, takich jak wycieki i wiszące uchwyty.
Wyzwanie
ŁatwyZbudujmy menedżer połączeń, który demonstruje RAII, automatycznie obsługując cykl życia połączeń podobnych do sieciowych. Gdy połączenie zostaje utworzone, powinno się „otworzyć”, a gdy wyjdzie poza zakres, powinno się automatycznie „zamknąć”: nie jest wymagane ręczne sprzątanie!
Utworzysz dwa pliki, aby uporządkować swój kod:
Connection.h: Zdefiniuj klasęConnection, która zarządza zasobem połączenia zgodnie z zasadami RAII. Klasa powinna mieć:- Prywatny atrybut
connectionId(string) służący do identyfikowania połączenia - Prywatny atrybut
isOpen(bool) służący do śledzenia stanu połączenia - Konstruktor, który przyjmuje identyfikator połączenia, ustawia
isOpenna true i wyświetla"Opening connection: <id>" - Destruktor, który sprawdza, czy połączenie jest otwarte, zamyka je, ustawiając
isOpenna false, i wyświetla"Closing connection: <id>" - Metodę
send(string message), która wyświetla"[<id>] Sending: <message>", jeśli połączenie jest otwarte - Metodę
getId(), która zwraca identyfikator połączenia
- Prywatny atrybut
main.cpp: Zademonstruj, jak RAII zapewnia automatyczne sprzątanie, odczytując z wejścia identyfikator połączenia i wiadomość. Następnie:- Utwórz zakres za pomocą nawiasów klamrowych
{ } - W tym zakresie utwórz na stosie obiekt
Connectionz wprowadzonym identyfikatorem - Użyj połączenia, aby wysłać wprowadzoną wiadomość
- Pozwól zakończyć się zakresowi (połączenie powinno zamknąć się automatycznie)
- Poza zakresem wyświetl
"Connection out of scope"
- Utwórz zakres za pomocą nawiasów klamrowych
Piękno RAII polega na tym, że nie musisz pamiętać o zamknięciu połączenia: destruktor obsługuje to automatycznie, gdy obiekt opuszcza zakres. Ten wzorzec zapobiega wyciekom zasobów, nawet jeśli w twoim kodzie wydarzy się coś nieoczekiwanego.
Dołącz plik nagłówkowy w main.cpp za pomocą #include "Connection.h".
Spróbuj swoich sił
#include <iostream>
#include <string>
#include "Connection.h"
using namespace std;
int main() {
string connectionId;
string message;
// Wczytaj dane wejściowe
cin >> connectionId;
cin.ignore();
getline(cin, message);
// TODO: Utwórz zakres za pomocą nawiasów klamrowych { }
// Wewnątrz zakresu:
// - Utwórz na stosie obiekt Connection z connectionId
// - Użyj połączenia, aby wysłać wiadomość
// Pozwól, aby zakres się zakończył (destruktor zostanie wywołany automatycznie)
// TODO: Po zakończeniu zakresu wypisz "Connection out of scope"
return 0;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneBudowanie i kompilacja C++Pliki nagłówkowe i pliki źródłowePrzestrzenie nazw i zakresWprowadzenie do programowania obiektowego w C++Klasy a obiektyWskaźnik „this”Metody (funkcje składowe)Atrybuty (składowe danych)Podstawy konstruktorów i destruktorówPowtórzenie – prosty kalkulator4Właściwości klas
Elementy instancji a elementy statyczneGettery i setteryStałe funkcje składoweSłowo kluczowe mutableMetody i zmienne statyczneFunkcje i klasy zaprzyjaźnionePodsumowanie – menedżer konta bankowego7Dziedziczenie
Podstawy dziedziczeniaPoziomy dostępu w dziedziczeniuKolejność wywołań konstruktora i destruktoraNadpisywanie metodFunkcje wirtualne i VTableWielokrotne dziedziczenieDziedziczenie wirtualnePowtórzenie — hierarchia pracowników2Zarządzanie pamięcią
Pamięć stosu a stertyWskaźniki i referencjePamięć dynamiczna (new/delete)Inteligentne wskaźniki w C++RAII w C++Podsumowanie — menedżer tablicy dynamicznej5Hermetyzacja
Specyfikatory dostępu w C++Specyfikatory dostępu — szczegółowoUkrywanie informacjiStruktura a klasaKlasy zagnieżdżone i wewnętrznePodsumowanie — system ewidencji studentów8Polimorfizm
Polimorfizm czasu kompilacji i wykonaniaPrzeciążanie funkcjiFunkcje wirtualne — powtórkaCzysto wirtualne funkcjeKlasy abstrakcyjneProjektowanie interfejsów w C++Rzutowanie dynamiczne i RTTIPodsumowanie — kalkulator kształtów3Konstruktory i destruktory
Konstruktor domyślnyKonstruktor z parametramiKonstruktor kopiującyKonstruktor przenoszącyListy inicjalizacyjne konstruktoraKonstruktory delegująceDestruktor — szczegółowe omówienieZasada trzech / pięciu / zeraPodsumowanie — klasa String6Przeciążanie operatorów
Wprowadzenie do przeciążania operatorówPrzeciążanie operatorów arytmetycznychPrzeciążanie operatorów porównaniaOperatory strumieniowePrzeciążanie operatora przypisaniaPrzeciążanie operatorów [] i ()Operatory konwersji typówPodsumowanie — klasa Matrix9Szablony
Szablony funkcjiSzablony klasSpecjalizacja szablonówSzablony wariadycznePodstawy SFINAE i cech typówPodsumowanie — kontener generycznyPoćwicz samodzielnie: Kompilator C++ online