Meséljen az exception dobás kihívásairól (throw exception) a konstruktorokban és destruktorokban.
sobes.tech MI
Válasz az MI-től
A kivétel hívása a konstruktorban erőforrás-szivárgáshoz vezethet, ha a objektumok vagy erőforrások egy része sikeresen lefoglalásra került a kivétel dobása előtt, és a megfelelő destruktor nem hívódik meg. Az szivárgások elkerülése érdekében ajánlott az RAII (Resource Acquisition Is Initialization) használata, például okos mutatók vagy csomagoló osztályok segítségével, amelyek garantálják az erőforrások felszabadítását a hatókörből való kilépéskor.
A destruktorban dobott kivétel viselkedése nem meghatározott. Ha a destruktor egy másik kivétel eredményeként hívódik meg (stack unwinding), és maga is kivételt dob, a program std::terminate-tel végződik. A C++ szabvány szerint a destruktoroknak noexcept-nak kell lenniük.
#include <iostream>
#include <memory> // std::unique_ptr
struct Resource {
Resource() { std::cout << "Erőforrás megszerzése\n"; }
~Resource() { std::cout << "Erőforrás felszabadítva\n"; }
};
struct BadConstructor {
Resource res; // Erőforrás a kivétel dobása előtt foglalva
BadConstructor() {
std::cout << "BadConstructor konstruktor\n";
throw std::runtime_error("Hiba a konstruktorban"); // Kivétel dobása
// A Resource destruktor nem hívódik meg, ha a kivétel a konstruktor végén dobódik
}
~BadConstructor() noexcept { // A destruktoroknak noexcept-nek kell lenniük
std::cout << "BadConstructor destruktor\n";
}
};
struct GoodConstructor {
std::unique_ptr<Resource> res; // Okos mutató RAII-hoz
GoodConstructor() : res(std::make_unique<Resource>()) {
std::cout << "GoodConstructor konstruktor\n";
// Ha kivétel dobódik, a unique_ptr garantálja a Resource destruktorának hívását a hatókörből való kilépéskor
// throw std::runtime_error("Hiba a konstruktorban");
}
~GoodConstructor() noexcept {
std::cout << "GoodConstructor destruktor\n";
}
};
struct BadDestructor {
BadDestructor() { std::cout << "BadDestructor konstruktor\n"; }
~BadDestructor() {
std::cout << "BadDestructor destruktor\n";
// Nem szabad kivételt dobni a destruktorból, különösen unwind közben
// throw std::runtime_error("Hiba a destruktorban");
}
};
int main() {
// Példa a konstruktorra (erőforrás szivárgáshoz vezethet RAII nélkül)
try {
// BadConstructor bc; // Kikommentelve a szivárgás demonstrálásához
} catch (const std::exception& e) {
std::cout << "Kivétel elkapva: " << e.what() << "\n";
}
// Példa a jó konstruktorra (RAII-t használ)
try {
// GoodConstructor gc; // Kikommentelve, nem lesz szivárgás
} catch (const std::exception& e) {
std::cout << "Kivétel elkapva: " << e.what() << "\n";
}
// Példa a destruktorra (akár std::terminate-hez vezethet)
try {
// BadDestructor bd; // Kikommentelve, ha a potenciális terminate-et akarod látni
// throw std::runtime_error("Másik kivétel"); // unwind-et okoz
} catch (const std::exception& e) {
std::cout << "Kivétel elkapva: " << e.what() << "\n";
}
return 0;
}
Táblázat:
| Kivétel hívás helye | Potenciális problémák | Ajánlott megoldás |
|---|---|---|
| Konstruktor | Erőforrás szivárgás | RAII használata (okos mutatók, csomagoló osztályok) |
| Destruktor | Nem meghatározott viselkedés, std::terminate unwind közben |
A destruktoroknak noexcept-nek kell lenniük, kerülje a kivétel dobását |