Sobes.tech
Middle+

რა შეგიძლიათ თქვათ კონსტრუქტორებში გამონაკლისების მუშაობის შესახებ?

sobes.tech AI

პასუხი AI-სგან

კონსტრუქტორის გამოძახებისას, თუ კლასის წევრის ინიციალიზაციის ან კონსტრუქტორის სხეულში გამოიწვევა გამონაკლისი, კონსტრუქტორის შესრულება შეწყდება:

თუ გამონაკლისი გამოიწვევა ობიექტის სრულად შექმნის წინ, ამ ობიექტის დესტრუქტორი არ გამოიძახება. ეს შეიძლება გამოიწვიოს რესურსების გაჟონვას, თუ კონსტრუქტორმა რესურსები გამოყო, მაგრამ ვერ მოასწრო მათი გათავისუფლება გამონაკლისის გამოყოფამდე:

გამონაკლისებთან მუშაობისას კონსტრუქტორებში მნიშვნელოვანია შემდეგი გაითვალისწინოთ:

  • რესურსების გაჟონვა: თუ კონსტრუქტორმა გამოყო რესურსები (მაგალითად, მეხსიერება, ფაილები) და შემდეგ გამოიწვია გამონაკლისი რესურსების გათავისუფლამდე, მოხდება გაჟონვა.
  • ნაწილობრივ შექმნილი ობიექტები: გამონაკლისის შემთხვევაში, ობიექტი შეიძლება იყოს არასრულად ინიციალიზებული. ასეთი ობიექტის მიმართვა შეიძლება გამოიწვიოს გაურკვეველი ქცევა.

უსაფრთხო მუშაობისთვის გამონაკლისებთან, გამოიყენება შემდეგი მიდგომები:

  • RAII (Resource Acquisition Is Initialization) პრინციპი: რესურსები ჩასმულია კლასებში, რომელთა კონსტრუქტორები მათ გამოყოფენ, ხოლო დესტრუქტორები გათავისუფლებენ. ამგვარად, გამონაკლისის გამოყოფისას, უკვე შექმნილი წევრების და ძირითადი კლასების დესტრუქტორები ავტომატურად გამოიძახება, რაც უზრუნველყოფს რესურსების გათავისუფლებას:

    // RAII-ის გამოყენების მაგალითი — ჭკვიანი მაჩვენებლით
    #include <memory>
    #include <iostream>
    
    class Resource {
    public:
        Resource() { std::cout << "რესურსი მიღებულია\n"; }
        ~Resource() { std::cout << "რესურსი გათავისუფლდა\n"; }
    };
    
    class MyClass {
        std::unique_ptr<Resource> res;
    public:
        MyClass() : res(std::make_unique<Resource>()) {
            // აქ შეიძლება გამოიწვიოს გამონაკლისი
            // თუ გამოიწვევა, unique_ptr-ი გაათავისუფლებს რესურსს
            if (true) { // მოდელის პირობა
                // throw std::runtime_error("შეცდომა კონსტრუქტორში");
            }
        }
    };
    
    // int main() {
    //     try {
    //         MyClass obj;
    //     } catch (const std::exception& e) {
    //         std::cerr << "გამოჭერილი გამონაკლისი: " << e.what() << std::endl;
    //     }
    //     return 0;
    // }
    
  • init() წევრი ფუნქცია: კონსტრუქტორში ხორციელდება მხოლოდ მარტივი ინიციალიზაცია, ხოლო უფრო რთული ლოგიკა, რომელიც შეიძლება გამოიწვიოს გამონაკლისი, გადადის init() წევრ ფუნქციაში, რომელიც გამოიძახება ობიექტის წარმატებული შექმნის შემდეგ:

    class MyClass {
        // კლასის წევრები
    public:
        MyClass() {
            // მარტივი ინიციალიზაცია, რომელიც არ გამოიწვევს გამონაკლისს
        }
    
        void init() {
            // უფრო რთული ლოგიკა, რომელიც შეიძლება გამოიწვიოს გამონაკლისი
            if (true) { // მოდელის პირობა
                // throw std::runtime_error("ინიციალიზაციის შეცდომა");
            }
        }
    };
    
    // int main() {
    //     try {
    //         MyClass obj;
    //         obj.init(); // გამოძახება ინიციალიზაციის შემდეგ
    //     } catch (const std::exception& e) {
    //         std::cerr << "გამოჭერილი გამონაკლისი: " << e.what() << std::endl;
    //     }
    //     return 0;
    // }
    
  • დელეგატორული კონსტრუქტორები (C++11 და ახალი): საშუალებას აძლევს კონსტრუქტორებს გამოიძახონ სხვა კონსტრუქტორები იგივე კლასი. ეს შეიძლება იყოს სასარგებლო ინიციალიზაციის ლოგიკის ცენტრალიზაციისთვის, მათ შორის გამონაკლისების წარმოქმნისთვის:

    class MyClass {
        int value;
    public:
        MyClass(int v) : value(v) {
            if (v < 0) {
                throw std::invalid_argument("მნიშვნელობა უნდა იყოს არასაკრედიტი");
            }
            // დამატებითი ინიციალიზაციის ლოგიკა
        }
    
        MyClass() : MyClass(0) {} // დელეგატური კონსტრუქტორი
    };
    
    // int main() {
    //     try {
    //         MyClass obj1(10);
    //         MyClass obj2(-5); // გამოიწვევს გამონაკლისს
    //     } catch (const std::exception& e) {
    //         std::cerr << "გამოჭერილი გამონაკლისი: " << e.what() << std::endl;
    //     }
    //     return 0;
    // }
    

არჩეული მეთოდი დამოკიდებულია ინიციალიზაციის სირთულეზე და კლასის სპეციფიკაზე. RAII სასურველია რესურსების მართვისთვის C++-ში.