Sobes.tech
Middle
201

Hogyan fordulhat elő memória szivárgás a unique_ptr használatakor C++-ban?

Válasz az MI-től

sobes.tech MI

A memória szivárgás a std::unique_ptr használatakor a következő esetekben fordulhat elő:

  1. Hibás saját deleter használata: Ha a saját deleter nem szabadítja fel helyesen az allokált erőforrást (például delete helyett delete[] tömbök esetén vagy nem hívja meg a megfelelő felszabadító függvényt).

    #include <memory>
    #include <iostream>
    
    struct MyDeleter {
        void operator()(int* ptr) const {
            // HIBÁS: delete[] kellene, nem delete
            delete ptr;
            std::cout << "Hibás deleter hívva" << std::endl;
        }
    };
    
    int main() {
        // Tömb lefoglalása, de hibás deleter használata
        std::unique_ptr<int, MyDeleter> ptr(new int[10], MyDeleter());
        // A tömbként lefoglalt memória nem kerül teljesen felszabadításra a scope elhagyásakor
        return 0;
    }
    
  2. Raw pointer átadása unique_ptr-ből egy olyan függvénynek, amely átveszi a tulajdonjogot és nem szabadítja fel: A tulajdonjogot egyértelműen std::move-val kell átadni. Ha get()-et vagy raw pointert adunk át, majd nem szabadítjuk fel, memória szivárgás léphet fel.

    #include <memory>
    #include <iostream>
    
    void process_and_lose(int* raw_ptr) {
        // A függvény "elfelejti" delete-t
        std::cout << "Feldolgozás " << *raw_ptr << std::endl;
        // Memória szivárgás!
    }
    
    int main() {
        std::unique_ptr<int> ptr(new int(42));
        int* raw = ptr.get();
        process_and_lose(raw);
        // A ptr még mindig kezeli a memóriát, de a raw_ptr már árva
        // Ebben a példában nincs szivárgás, mert a ptr felszabadítja a memóriát
        // De ha a ptr-t resetelnénk vagy átírnánk a hívás előtt, szivárgás történne
        return 0;
    }
    

    Javított példa potenciális szivárgással (ha átadjuk a tulajdonjogot, de a függvény nem szabadít fel):

    #include <memory>
    #include <iostream>
    
    void function_that_takes_ownership_and_leaks(int* owned_ptr) {
        // Feltételezzük, hogy az owned_ptr mostantól ennek a függvénynek a tulajdona
        std::cout << "Tulajdon átvétele és szivárgás: " << *owned_ptr << std::endl;
        // Szivárgás: owned_ptr nem kerül delete-re
    }
    
    int main() {
        std::unique_ptr<int> ptr(new int(100));
        // Tulajdonjog átadása raw pointer-rel
        function_that_takes_ownership_and_leaks(ptr.release());
        // A ptr most üres, az erőforrása (a pointer) nem lesz automatikusan felszabadítva
        return 0;
    }
    
  3. Memória szivárgás a memória lefoglalása és unique_ptr-be csomagolása között kivétel esetén: Bár a std::make_unique ezt megelőzi, a közvetlen new használata és a unique_ptr-be csomagolás között kivétel léphet fel, ami szivárgáshoz vezethet.

    #include <memory>
    #include <vector>
    
    class Resource { public: Resource() { std::cout << "Erőforrás létrehozva" << std::endl;} ~Resource() { std::cout << "Erőforrás megsemmisítve" << std::endl;} };
    void might_throw() { throw std::runtime_error("Hoppá!"); }
    
    int main() {
        Resource* res = new Resource(); // Memória lefoglalása
        try {
            might_throw(); // Kivétel itt keletkezik
            std::unique_ptr<Resource> ptr(res); // Ez a sor nem fog végrehajtódni
        } catch (const std::runtime_error& e) {
            std::cerr << "Kivétel elkapva: " << e.what() << std::endl;
            // res* nem volt csomagolva `unique_ptr`-be és nem lett delete-elve
            // Ez memória szivárgáshoz vezet!
        }
        // Helyes mód: std::make_unique<Resource>() vagy std::unique_ptr<Resource> ptr(new Resource());
        return 0;
    }
    

Általánosságban elmondható, hogy a memória szivárgás a std::unique_ptr helyes használatakor rendkívül ritka, mivel fő célja az erőforrások automatikus kezelése, amely megakadályozza a szivárgásokat tipikus esetekben. A problémák akkor fordulnak elő, amikor a szokásos használat határain túl megyünk (egyedi deleterek, release(), raw pointer-ekkel való interakció).