Sobes.tech
Middle

C++ da unique_ptr ishlatilganda qanday qilib xotira oqishini oldini olish mumkin?

sobes.tech AI

AIdan javob

std::unique_ptr bilanotlarining to'kilishi quyidagi holatlarda yuzaga kelishi mumkin:

  1. Maxsus o'chirishchi (Deleter) noto'g'ri ishlatilishi: Agar maxsus o'chirishchi to'g'ri tarzda ajratilgan resursni bo'shatmasa (masalan, massiv uchun delete o'rniga delete[] chaqirmasa yoki mos bo'shatish funksiyasini chaqirmasa).

    #include <memory>
    #include <iostream>
    
    struct MyDeleter {
        void operator()(int* ptr) const {
            // XATO: delete[] bo'lishi kerak, delete emas
            delete ptr;
            std::cout << "Noto'g'ri o'chirishchi chaqirildi" << std::endl;
        }
    };
    
    int main() {
        // Massiv ajratildi, ammo noto'g'ri o'chirishchi ishlatilgan
        std::unique_ptr<int, MyDeleter> ptr(new int[10], MyDeleter());
        // Massiv sifatida ajratilgan xotira ptr tashqariga chiqgach to'liq bo'shatilmaydi
        return 0;
    }
    
  2. unique_ptr dan olingan xom ko'rsatkichni, uni egallagan va bo'shatmaydigan funksiyaga o'tkazish: Egallashni aniq std::move yordamida qilish kerak. Agar get() yoki xom ko'rsatkich o'tkazilsa va uni boshqa joyda bo'shatmasangiz, bu xotira oqishiga olib kelishi mumkin.

    #include <memory>
    #include <iostream>
    
    void process_and_lose(int* raw_ptr) {
        // Funksiya "delete" ni unutdi
        std::cout << "Qayta ishlash " << *raw_ptr << std::endl;
        // Xotira oqishi!
    }
    
    int main() {
        std::unique_ptr<int> ptr(new int(42));
        // Xom ko'rsatkich olamiz
        int* raw = ptr.get();
        process_and_lose(raw);
        // ptr hali ham xotirani boshqaradi, ammo raw_ptr yolg'onga aylandi
        // Bu holatda, `ptr` xotirani bo'shatadi, lekin `raw_ptr` bo'sh qoladi
        // Agar `ptr` oldindan reset qilinsa yoki qayta tayinlansa va funksiya uni o'chirmasa, oqish yuzaga keladi
        return 0;
    }
    

    To'g'irlangan misol, egallashni o'tkazib yuborgan va oqish ehtimoli bo'lgan holatda:

    #include <memory>
    #include <iostream>
    
    void function_that_takes_ownership_and_leaks(int* owned_ptr) {
        // Bu funksiya endi owned_ptr ga egalik qiladi deb faraz qilamiz
        std::cout << "Egallash va oqish: " << *owned_ptr << std::endl;
        // Oqish: owned_ptr o'chirilmaydi
    }
    
    int main() {
        std::unique_ptr<int> ptr(new int(100));
        // Xom ko'rsatkich egallash va o'tkazish
        function_that_takes_ownership_and_leaks(ptr.release());
        // ptr endi bo'sh, uning resursi (ko'rsatkich) avtomatik ravishda bo'shatilmaydi
        return 0;
    }
    
  3. Xotira ajratish va unique_ptr ga o'rash orasida istisnolar: std::make_unique buni oldini oladi, lekin to'g'ridan-to'g'ri new ishlatish va keyin unique_ptr konstruktoridan foydalanish, ular orasida istisno yuzaga kelsa, oqishga olib kelishi mumkin.

    #include <memory>
    #include <vector>
    
    class Resource { public: Resource() { std::cout << "Resurs yaratildi" << std::endl;} ~Resource() { std::cout << "Resurs yo'q qilindi" << std::endl;} };
    void might_throw() { throw std::runtime_error("OOPS!"); }
    
    int main() {
        Resource* res = new Resource(); // Xotira ajratish
        try {
            might_throw(); // Bu yerda istisno yuzaga keladi
            std::unique_ptr<Resource> ptr(res); // Bu satrga yetib borilmaydi
        } catch (const std::runtime_error& e) {
            std::cerr << "Uchyotga olindi: " << e.what() << std::endl;
            // res* unique_ptr ga o'ralmagan va yo'q qilinmagan
            // Bu oqishga olib keladi!
        }
        // To'g'ri usul: std::make_unique<Resource>() yoki std::unique_ptr<Resource> ptr(new Resource());
        return 0;
    }
    

Umuman olganda, std::unique_ptr bilan to'g'ri foydalanish bilan xotira oqishi juda kam ehtimol, chunki uning asosiy maqsadi resurslarni avtomatik boshqarish va odatiy holatlarda oqishni oldini olishdir. Muammolar uning standart foydalanish chegaralaridan chiqib ketganda yuzaga keladi (maxsus o'chirishchilar, release(), xom ko'rsatkichlar bilan ishlash).