გააზიარეთ კონსტრუქტორებსა და დესტრუქტორებში გამონაკლისების გადაყრის გამოწვევები.
sobes.tech AI
პასუხი AI-სგან
კონსტრუქტორში გამონაკლისის გამოძახება შეიძლება გამოიწვიოს რესურსების გაჟონვა, თუ ობიექტების ან რესურსების ნაწილი კონსტრუქტორში წარმატებით დაითმინა გამონაკლისის გაშვების წინ, ხოლო შესაბამისი დესტრუქტორი ამ დროს არ გამოიძახება. გაჟონვის თავიდან ასაცილებლად რეკომენდებულია RAII (Resource Acquisition Is Initialization) გამოყენება, მაგალითად, ჭკვიანი მაჩვენებლების ან ქლასების გამოყენებით, რომლებიც გარანტირებულია რესურსების გათავისუფლებას გამოსვლისას.
დესტრუქტორში გამონაკლისის გამოძახება იწვევს არაზუსტ ქცევას. თუ დესტრუქტორი გამოიძახება სხვა გამონაკლისის შედეგით (stack unwinding), და ამ დროს ის თვითონ გამოიწვევს გაუმკლავებელ გამონაკლისს, პროგრამა დასრულდება std::terminate-ის გამოძახებით. C++ სტანდარტის მიხედვით, დესტრუქტორები უნდა იყოს noexcept.
#include <iostream>
#include <memory> // std::unique_ptr-ისთვის
სტრუქტურა Resource {
Resource() { std::cout << "Resource მიღებულია\n"; }
~Resource() { std::cout << "Resource გათავისუფლებულია\n"; }
};
სტრუქტურა BadConstructor {
res რესურსი; // რესურსი დაითმინება გამონაკლისის გაშვების წინ
BadConstructor() {
std::cout << "BadConstructor კონსტრუქტორი\n";
throw std::runtime_error("შეცდომა კონსტრუქტორში"); // გამონაკლისის გამოძახება
// Resource დესტრუქტორი არ გამოიძახება, თუ გამონაკლისი გამოიწვია კონსტრუქტორში
}
~BadConstructor() noexcept { // დესტრუქტორებმა უნდა იყოს noexcept
std::cout << "BadConstructor დესტრუქტორი\n";
}
};
სტრუქტურა GoodConstructor {
std::unique_ptr<Resource> res; // ჭკვიანი მაჩვენებელი RAII-ისთვის
GoodConstructor() : res(std::make_unique<Resource>()) {
std::cout << "GoodConstructor კონსტრუქტორი\n";
// ახლა, თუ გამოიწვევს გამონაკლისს, unique_ptr გარანტირებულია Resource-ის დესტრუქტორის გამოძახება გამოსვლისას
// throw std::runtime_error("შეცდომა კონსტრუქტორში");
}
~GoodConstructor() noexcept {
std::cout << "GoodConstructor დესტრუქტორი\n";
}
};
სტრუქტურა BadDestructor {
BadDestructor() { std::cout << "BadDestructor კონსტრუქტორი\n"; }
~BadDestructor() {
std::cout << "BadDestructor დესტრუქტორი\n";
// გამონაკლისის გამოძახება დესტრუქტორიდან არ შეიძლება, განსაკუთრებით unwind-ის დროს
// throw std::runtime_error("შეცდომა დესტრუქტორში");
}
};
int main() {
// მაგალითი კონსტრუქტორში (გააკეთებს Resource-ის გაჟონვას RAII-ის გარეშე)
try {
// BadConstructor bc; // გააქტიურეთ გაჟონვის დემონსტრაციისთვის
} catch (const std::exception& e) {
std::cout << "დაკავებული გამონაკლისი: " << e.what() << "\n";
}
// მაგალითი კარგი კონსტრუქტორით (გამოყენებულია RAII)
try {
// GoodConstructor gc; // გააქტიურეთ გაჟონვის გარეშე
} catch (const std::exception& e) {
std::cout << "დაკავებული გამონაკლისი: " << e.what() << "\n";
}
// მაგალითი დესტრუქტორით (შესაძლოა გამოიწვიოს std::terminate)
try {
// BadDestructor bd; // გააქტიურეთ, თუ გსურთ ნახოთ პოტენციური terminate
// throw std::runtime_error("სხვა გამონაკლისი"); // გამონაკლისი, რომელიც გამოიწვევს unwind-ს
} catch (const std::exception& e) {
std::cout << "დაკავებული გამონაკლისი: " << e.what() << "\n";
}
return 0;
}