Close Menu
    Ciekawe

    Opera Portable – przeglądarka internetowa na pendrive bez instalacji

    2026-03-09

    doPDF – wirtualna drukarka do konwersji dokumentów na PDF

    2026-03-08

    Kaspersky Free – podstawowa ochrona antywirusowa za darmo

    2026-03-07
    Facebook X (Twitter) Instagram
    CPP Polska
    Facebook X (Twitter) Instagram
    • Biznes

      Programy VPN – ranking, porównanie i poradnik wyboru (2026)

      2026-02-26

      Obrót, przychód i dochód firmy – czym się różnią i jak je obliczyć?

      2026-02-16

      Restrukturyzacja i upadłość firmy – na czym polegają i jakie są konsekwencje?

      2026-02-14

      Składki ZUS dla firmy jednoosobowej w 2025 roku – ile wynoszą i jak je obliczyć?

      2026-01-28

      Co powinna zawierać pieczątka firmy jednoosobowej? Wymogi prawne i wzór

      2025-12-28
    • Technologie

      Opera Portable – przeglądarka internetowa na pendrive bez instalacji

      2026-03-09

      doPDF – wirtualna drukarka do konwersji dokumentów na PDF

      2026-03-08

      Kaspersky Free – podstawowa ochrona antywirusowa za darmo

      2026-03-07

      PeaZip – darmowy program do otwierania archiwów ZIP i RAR

      2026-03-05

      Jak oglądać filmy VR na komputerze? Wymagania i instrukcja

      2026-03-04
    • Programowanie

      Maszyna stanów oparta o std::variant

      2025-10-07

      std::deque w C++ – kiedy wybrać dwukierunkową kolejkę zamiast vectora

      2025-10-07

      Tablice w C++ od podstaw – deklaracja, inicjalizacja, iteracja i typowe pułapki

      2025-10-07

      itoa i std::to_chars – konwersja liczb na tekst bez narzutu wydajności

      2025-10-07

      strcpy vs strncpy vs std::string – bezpieczne kopiowanie łańcuchów w C++

      2025-10-07
    • Inne

      eSIM w Mobile Vikings – jak wirtualna karta SIM daje Ci wolność bez plastiku, kuriera i wychodzenia z domu

      2025-12-16

      Jak prowadzić blog programistyczny i dzielić się wiedzą?

      2025-06-28
    • Programy VPN – ranking
    CPP Polska
    Home»C++»Kompendium wiedzy o smart-pointerach w C++
    C++

    Kompendium wiedzy o smart-pointerach w C++

    Oskar KlimkiewiczBy Oskar KlimkiewiczBrak komentarzy5 Mins Read
    Share Facebook Twitter LinkedIn Email Copy Link
    Follow Us
    RSS
    a computer screen with a plant on it
    Share
    Facebook Twitter LinkedIn Email Copy Link

    Kompendium wiedzy o smart pointerach w C++ – zarządzanie pamięcią w erze nowoczesnego C++

    Wstęp – ewolucja zarządzania pamięcią w C++

    Smart pointery w C++ reprezentują fundamentalną zmianę w zarządzaniu pamięcią, wprowadzając automatyczne zarządzanie cyklem życia obiektów poprzez RAII (Resource Acquisition Is Initialization). Historycznie, zarządzanie pamięcią w C++ opierało się na ręcznej alokacji i zwalnianiu zasobów za pomocą operatorów new/delete, co prowadziło do wycieków pamięci, podwójnego zwalniania i błędów związanych z nieprawidłowymi wskaźnikami. Wraz ze standardem C++11 wprowadzono trzy główne typy inteligentnych wskaźników: unique_ptr, shared_ptr i weak_ptr, zaimplementowane w nagłówku <memory>. Mechanizmy te nie tylko automatyzują zwalnianie pamięci, ale także wyrażają semantykę własności w sposób czytelny dla programisty i kompilatora. Kluczową zaletą smart pointerów jest ich zgodność z kontenerami Standard Template Library (STL), umożliwiająca bezpieczne przechowywanie dynamicznie alokowanych obiektów w strukturach takich jak std::vector czy std::map.

    Unikalna własność z std::unique_ptr

    std::unique_ptr gwarantuje wyłączną własność zasobu, zapewniając, że tylko jedna instancja unique_ptr może posiadać dany obiekt w danym czasie. Implementacja wykorzystuje semantykę przenoszenia (move semantics), co pozwala na efektywne przekazywanie własności bez narzutu wydajnościowego. Rozmiar unique_ptr jest identyczny jak surowego wskaźnika (jeden wskaźnik), co czyni go najlżejszym rozwiązaniem wśród smart pointerów.

    Praktyczne zastosowania i składnia:

    // Tworzenie unique_ptr do obiektu
    auto widget = std::make_unique<Widget>(); // C++14+
    // Przenoszenie własności
    auto newOwner = std::move(widget);
    // Przechowywanie w kontenerach
    std::vector<std::unique_ptr<Widget>> container;
    container.push_back(std::make_unique<Widget>());
    

    W przypadku tablic, unique_ptr obsługuje alokacje typu T[] z poprawnym zwalnianiem pamięci za pomocą delete[]:

    auto arr = std::make_unique<int[]>(10); // Alokacja tablicy
    

    Zalecenie – zawsze preferuj std::make_unique (dostępne od C++14) dla bezpieczeństwa wyjątków i optymalizacji.

    Współdzielona własność z std::shared_ptr

    std::shared_ptr implementuje własność współdzieloną poprzez zliczanie referencji (reference counting). Mechanizm ten pozwala wielu instancjom shared_ptr zarządzać tym samym obiektem, który jest niszczony, gdy licznik referencji osiągnie zero. Wewnętrznie, shared_ptr składa się z dwóch wskaźników: do zarządzanego obiektu i do bloku kontrolnego zawierającego licznik referencji i deleter. Rozmiar to dwa wskaźniki (zwykle 16 bajtów na architekturach 64-bitowych).

    Implementacja licznika referencji:

    Blok kontrolny zawiera:

    • shared_count – licznik „silnych” referencji (shared_ptr);
    • weak_count – licznik „słabych” referencji (weak_ptr). Destrukcja obiektu następuje, gdy shared_count osiągnie zero, podczas gdy blok kontrolny jest zwalniany dopiero, gdy oba liczniki wynoszą zero.

    Tworzenie i zalecenia:

    // Optymalna alokacja: make_shared alokuje obiekt i blok kontrolny w jednym bloku
    auto obj = std::make_shared<Widget>();
    // Niezalecane: oddzielna alokacja obiektu i bloku kontrolnego
    std::shared_ptr<Widget> obj2(new Widget()); // Mniej wydajne
    

    Kluczowa zasada – używaj std::make_shared zamiast jawnego new dla redukcji alokacji pamięci i poprawy lokalności referencyjnej.

    Słabe referencje z std::weak_ptr

    std::weak_ptr rozwiązuje kluczowe problemy związane ze shared_ptr: cykliczne zależności i niekontrolowane wydłużanie życia obiektów. weak_ptr nie zwiększa licznika referencji, lecz pozwala na „podgląd” obiektu zarządzanego przez shared_ptr. Aby uzyskać dostęp do obiektu, weak_ptr musi zostać przekonwertowany na shared_ptr metodą lock().

    Przykład rozwiązywania cyklów:

    class Node {
    public:
        std::shared_ptr<Node> parent;
        std::weak_ptr<Node> child; // Słaba referencja do uniknięcia cyklu
    };
    

    Gdy child jest weak_ptr, zniszczenie węzła nadrzędnego skutkuje poprawnym zwolnieniem pamięci przez mechanizm zliczania referencji.

    Bezpieczny dostęp:

    auto sharedChild = child.lock();
    if (sharedChild) {
        // Bezpieczne użycie sharedChild
    } else {
        // Obiekt już nie istnieje
    }
    

    Niestandardowe deletery – rozszerzona kontrola zwracania zasobów

    Smart pointery pozwalają na definiowanie niestandardowych deleterów dla zasobów niebędących pamięcią (np. pliki, gniazda sieciowe). Deleter to obiekt wywoływalny (funkcja, lambda, funktor) przekazany w konstruktorze.

    Przykład dla zasobów Win32 API:

    struct FileDeleter {
        void operator()(FILE* file) const {
            if (file) fclose(file);
        }
    };
    std::unique_ptr<FILE, FileDeleter> filePtr(fopen("data.txt", "r"));
    

    W przypadku shared_ptr, deleter jest przechowywany w bloku kontrolnym, co eliminuje potrzebę dodatkowej alokacji pamięci.

    Bezpieczeństwo wątkowe i wydajność

    • Thread safety – operacje atomowe na liczniku referencji w shared_ptr są bezpieczne wątkowo, lecz dostęp do samego obiektu wymaga zewnętrznej synchronizacji (np. mutexów);
    • Wydajność –
    • unique_ptr: zerowy narzut względem surowego wskaźnika,
    • shared_ptr: koszt związany z atomowym inkrementacją/dekrementacją licznika i podwójną alokacją (obiekt + blok kontrolny). make_shared redukuje to do jednej alokacji,
    • weak_ptr: minimalny narzut (jeden dodatkowy wskaźnik).

    Zaawansowane wzorce i ostrzeżenia

    std::enable_shared_from_this

    Wzorzec umożliwia obiektowi bezpieczne generowanie shared_ptr z poziomu swoich metod. Wymaga publicznego dziedziczenia:

    class Session : public std::enable_shared_from_this<Session> {
    public:
        void process() {
            auto self = shared_from_this(); // Bezpieczne pozyskanie shared_ptr
        }
    };
    

    Ograniczenia – nie wolno wywoływać shared_from_this() w konstruktorze ani gdy obiekt nie jest zarządzany przez shared_ptr.

    Typowe błędy:

    1. Nadużywanie shared_ptr – preferuj unique_ptr tam, gdzie nie jest wymagane współdzielenie własności;
    2. Cykl referencji – wykrywaj i przerywaj cykle za pomocą weak_ptr;
    3. Tworzenie z this –
    
    // BŁĄD: nowy blok kontrolny dla istniejącego obiektu!
    std::shared_ptr<Widget> ptr(raw_ptr);
    
    1. Mieszanie surowych wskaźników i smart pointerów – prowadzi do podwójnego usuwania.

    Podsumowanie – wybór narzędzia

    Typ Przypadek użycia Wydajność Bezpieczeństwo
    unique_ptr Wyłączna własność, zasoby lokalne Zerowy narzut Wysokie
    shared_ptr Współdzielona własność, zasoby globalne Średni narzut Średnie*
    weak_ptr Obserwacja, przerywanie cykli Minimalny narzut Wysokie
    * Wymaga synchronizacji dla dostępu do obiektu w wątkach.

    Smart pointery są nieodzownym elementem nowoczesnego C++, zapewniając bezpieczeństwo pamięci bez rezygnacji z wydajności. Ich poprawne stosowanie wymaga zrozumienia semantyki własności i charakterystyki wydajnościowej. Przestrzeganie zasad RAII i preferowanie make_shared/make_unique to klucz do efektywnego i bezpiecznego kodu.

    Polecane:

    • RAII w C++ – zbiór najlepszych praktyk
    • Semantyka przenoszenia i std::move – zarządzanie zasobami w C++
    • Cykl życia obiektów i wskaźniki this w C++
    • RAII i obsługa wyjątków – zarządzanie zasobami w C++
    • Późna inicjalizacja obiektów w C++ – lista inicjalizacyjna i inne techniki
    Share. Facebook Twitter LinkedIn Email Copy Link
    Oskar Klimkiewicz
    • Website

    Inżynier oprogramowania specjalizujący się w C++, absolwent Wydziału Elektroniki i Technik Informacyjnych Politechniki Warszawskiej. Od ponad 8 lat projektuje i rozwija systemy o wysokiej dostępności, głównie dla branży fintech i IoT. PS. Zdjęcie wyretuszowane przez AI :)

    Podobne artykuły

    Maszyna stanów oparta o std::variant

    8 Mins Read

    Tablice w C++ od podstaw – deklaracja, inicjalizacja, iteracja i typowe pułapki

    4 Mins Read

    std::deque w C++ – kiedy wybrać dwukierunkową kolejkę zamiast vectora

    4 Mins Read
    Leave A Reply Cancel Reply

    Oglądaj, słuchaj, ćwicz - zdobywaj nowe umiejętności online
    Nie przegap

    Opera Portable – przeglądarka internetowa na pendrive bez instalacji

    Oskar Klimkiewicz4 Mins Read

    W erze mobilności i pracy zdalnej Opera Portable staje się nieocenionym narzędziem dla użytkowników, którzy…

    doPDF – wirtualna drukarka do konwersji dokumentów na PDF

    2026-03-08

    Kaspersky Free – podstawowa ochrona antywirusowa za darmo

    2026-03-07

    PeaZip – darmowy program do otwierania archiwów ZIP i RAR

    2026-03-05
    Social media
    • Facebook
    • Twitter
    • LinkedIn
    O nas
    O nas

    CPP Polska to serwis internetowy poświęcony technologii, programowaniu, IT, biznesowi i finansom. Znajdziesz tu porady, wskazówki i instrukcje dla wszystkich czytelników IT & Tech & Biz.

    Facebook X (Twitter) LinkedIn RSS
    Najnowsze

    Opera Portable – przeglądarka internetowa na pendrive bez instalacji

    2026-03-09

    doPDF – wirtualna drukarka do konwersji dokumentów na PDF

    2026-03-08

    Kaspersky Free – podstawowa ochrona antywirusowa za darmo

    2026-03-07
    Popularne

    Skrajnie niepotrzebne, skrajne przypadki w C++

    2025-06-28

    Wyszukiwanie testów w Google Test – metody i narzędzia

    2025-06-28

    Czy C jest wolniejszy od C++? Zero-cost abstraction w praktyce

    2025-06-28
    © 2026 CPP Polska. Wszelkie prawa zastrzeżone.
    • Lista publikacji
    • Współpraca
    • Kontakt

    Type above and press Enter to search. Press Esc to cancel.