Narzędzia użytkownika

Narzędzia witryny


smart_ptr

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Next revision
Previous revision
smart_ptr [2008/04/16 01:16]
wodny utworzono
smart_ptr [2008/10/23 11:03] (aktualna)
rnowak2
Linia 1: Linia 1:
-''​+{{smart_ptr_latin2.cpp|}} 
 +<code cpp> 
 +
 + * Autor: Marcin Szewczyk, 198370 
 + * 
 + * Temat: smart_ptr 
 + * 
 + * Inteligentne wskaźniki zawarte w module smart_ptr biblioteki boost. 
 + * Sposób ich wykorzystania,​ różnice pomiędzy poszczególnymi typami wskaźników,​  
 + * nieco ciekawostek,​ które nie rzucają się od razu w oczy. 
 + * 
 + * Chociaż ten plik jest dość długi zawiera tylko garść informacji. Pełna  
 + * dokumentacja,​ na której opierałem się pisząc ten program jest tu: 
 + * http://​www.boost.org/​doc/​libs/​1_35_0/​libs/​smart_ptr/​smart_ptr.htm 
 + * 
 + * Omówione tutaj typy inteligentnych wskaźników to: 
 + ​* ​ - scoped_ptr 
 + ​* ​ - scoped_array 
 + ​* ​ - shared_ptr 
 + ​* ​ - weak_ptr 
 + ​* ​ - intrusive_ptr 
 + ​* ​ - oraz std::​auto_ptr nienależący do bibl. boost, ale warty porównania 
 + * 
 + ​* ​ nie został opisany typ shared_array,​ ponieważ nie wnosi nic nowego do  
 + ​* ​ omawianych tu zagadnień 
 + * 
 + ​* ​ Changelog:​ 
 + ​* ​ 2008.10.18 ​ W końcu poprawiłem mały wyciek pamięci w miejscu, w którym 
 + ​* ​             nie użyłem smart_ptr - o ironio! 
 + * 
 + ​* ​ Dobre rady: 
 + ​* ​ W tym dokumencie prezentowany jest wyciek pamięci w przypadku cykli 
 + ​* ​ budowanych na shared_ptr i jego brak w przypadku cykli budowanych na 
 + ​* ​ weak_ptr. Można uzyskać dobrą wizualizację zagadnienia przy pomocy 
 + ​* ​ aplikacji valgrind, 
 + ​* ​ Proponowany sposób użycia: 
 + ​* ​ valgrind --leak-check=full ./smart_ptr > /dev/null 
 + ​* ​ Efekt: 
 + ​* ​     114 (12 direct, 102 indirect) bytes in 1 blocks are definitely lost in loss 
 +record 3 of 5 
 + ​* ​       at 0x4023294: operator new(unsigned) (vg_replace_malloc.c:​224) 
 + ​* ​       by 0x8049AAE: shared_cycle() (smart_ptr.cpp:​474) 
 + ​* ​       by 0x804B5C6: main (smart_ptr.cpp:​608) 
 + * 
 + ​* ​ Support: 
 + ​* ​     wodny@thlen.pl <- usuń h 
 + */
  
-''​+#include <​cstdio>​ 
 +#include <​iostream>​ 
 +#include <​cstring>​ 
 +#include <​boost/​scoped_ptr.hpp>​ 
 +#include <​boost/​scoped_array.hpp>​ 
 +#include <​boost/​shared_ptr.hpp>​ 
 +#include <​boost/​weak_ptr.hpp>​ 
 +#include <​boost/​intrusive_ptr.hpp>​ 
 +#include <​boost/​enable_shared_from_this.hpp>​ 
 +#include <​vector>​ 
 +#include <​exception>​ 
 + 
 +// ========================================================== 
 +// Klasy potrzebne do prezentacji podstawowych cech inteligentnych wskaźników 
 + 
 +class Harry { 
 +        public: 
 +                Harry(const char* = NULL); 
 +                ~Harry(); 
 + 
 +                void hello(); 
 +        private: 
 +                char *name; 
 +}; 
 + 
 + 
 +class Betty : public Harry { 
 +        public: 
 +                Betty(); 
 +                ~Betty(); 
 +}; 
 + 
 +// ---------------------------------------------------------- 
 + 
 +Harry::​Harry(const char *name_) { 
 +        name = name_ ? strdup(name_) : NULL; 
 +        printf("​-- Constructing Harry (%s)\n",​ name); 
 +
 + 
 +Harry::​~Harry() { 
 +        printf("​-- Deconstructing Harry (%s)\n",​ name); 
 +        free(name);​ 
 +
 + 
 +void Harry::​hello() { 
 +        printf("​-- Harry \"​%s\"​ says hello\n",​ name); 
 +
 + 
 +// ---------------------------------------------------------- 
 + 
 +Betty::​Betty() { 
 +        printf("​---- Constructing Betty\n"​);​ 
 +
 + 
 +Betty::​~Betty() { 
 +        printf("​---- Deconstructing Betty\n"​);​ 
 +
 + 
 +// ========================================================== 
 +// Klasa, która posłuży do prezentacji,​ jak radzą sobie inteligentne wskaźniki z  
 +// cyklami 
 +// 
 +// Wariant dla cyklu z użyciem shared_ptr 
 + 
 +class RingNode { 
 +        public: 
 +                RingNode(const char*, const boost::​shared_ptr<​RingNode>&​);​ 
 +                ~RingNode();​ 
 +                void connect(const boost::​shared_ptr<​RingNode>&​);​ 
 +                const char* get_name();​ 
 +                const boost::​shared_ptr<​RingNode>&​ get_node();​ 
 +        private: 
 +                boost::​shared_ptr<​RingNode>​ node; 
 +                char* name; 
 +}; 
 + 
 +RingNode::​RingNode(const char* name_, const boost::​shared_ptr<​RingNode>&​ node_) : 
 +node(node_) { 
 +        name = name_ ? strdup(name_) : NULL; 
 +        printf("​++ Constructing RingNode (%s)\n",​ name); 
 +
 + 
 +RingNode::​~RingNode() { 
 +        printf("​++ Deconstructing RingNode (%s)\n",​ name); 
 +        free(name);​ 
 +
 + 
 +void RingNode::​connect(const boost::​shared_ptr<​RingNode>&​ node_) { 
 +        node = node_; 
 +
 + 
 +const char* RingNode::​get_name() { 
 +        return name; 
 +
 + 
 +const boost::​shared_ptr<​RingNode>&​ RingNode::​get_node() { 
 +        return node; 
 +
 + 
 +// ---------------------------------------------------------- 
 +// Wariant cyklu z weak_ptr 
 + 
 +class WeakRingNode { 
 +        public: 
 +                WeakRingNode(const char*, const boost::​shared_ptr<​WeakRingNode>&​);​ 
 +                ~WeakRingNode();​ 
 +                void connect(const boost::​shared_ptr<​WeakRingNode>&​);​ 
 +                const char* get_name();​ 
 +                const boost::​shared_ptr<​WeakRingNode>​ get_node();​ 
 +        private: 
 +                boost::​weak_ptr<​WeakRingNode>​ node; 
 +                char* name; 
 +}; 
 + 
 +WeakRingNode::​WeakRingNode(const char* name_, const boost::​shared_ptr<​WeakRingNode>&​ 
 +node_) : node(node_) { 
 +        name = name_ ? strdup(name_) : NULL; 
 +        printf("​++ Constructing RingNode (%s)\n",​ name); 
 +
 + 
 +WeakRingNode::​~WeakRingNode() { 
 +        printf("​++ Deconstructing RingNode (%s)\n",​ name); 
 +        free(name);​ 
 +
 + 
 +void WeakRingNode::​connect(const boost::​shared_ptr<​WeakRingNode>&​ node_) { 
 +        node = node_; 
 +
 + 
 +const char* WeakRingNode::​get_name() { 
 +        return name; 
 +
 + 
 +const boost::​shared_ptr<​WeakRingNode>​ WeakRingNode::​get_node() { 
 +        return node.lock();​ 
 +
 + 
 +// ========================================================== 
 +// Klasa potrzebna do prezentacji intrusive_ptr 
 +//  czyli sama zwiększa/​zmniejsza ilość referencji do danego obiektu na zlecenie  
 +//  intrusive_ptr oraz sama odpowiada za zniszczenie obiektu, gdy ilość odwołań  
 +//  spadnie do zera 
 + 
 +class Intruded { 
 +        public: 
 +                Intruded();​ 
 +                ~Intruded();​ 
 +        private: 
 +                int counter; 
 + 
 +                friend void intrusive_ptr_add_ref(Intruded *const); 
 +                friend void intrusive_ptr_release(Intruded *const); 
 +}; 
 + 
 +void intrusive_ptr_add_ref(Intruded *const); 
 +void intrusive_ptr_release(Intruded *const); 
 + 
 +// ---------------------------------------------------------- 
 + 
 +Intruded::​Intruded() : counter(0) { 
 +        printf("​%% Creating Intruded\n"​);​ 
 +
 + 
 +Intruded::​~Intruded() { 
 +        printf("​%% Destroying Intruded\n"​);​ 
 +
 + 
 +// Jak widać, licznik jest składową klasy, natomiast funkcje odpowiedzialne za  
 +// zliczanie - nie. 
 +// Na podstawie typu parametru, intrusive pointer wybiera odpowiedni zestaw  
 +// funkcji do inkrementacji i dekrementacji ilości odwołań 
 + 
 +void intrusive_ptr_add_ref(Intruded *const p) { 
 +        printf("​%% Added. Now: %d\n", ++(p->​counter));​ 
 +
 + 
 +void intrusive_ptr_release(Intruded *const p) { 
 +        printf("​%% Removed. Now: %d\n", --(p->​counter));​ 
 +        if(!p->​counter) { 
 +                printf("​%% Deleting Intruded because of count == 0...\n"​);​ 
 +                delete p; 
 +        } 
 +
 + 
 +// ========================================================== 
 +// Jak uzyskać poprawny (pod względem zliczania odwołań) shared_ptr do obiektu  
 +// nie mając wiedzy na temat tego, czy już jakiś inny shared_ptr się do niego  
 +// odwołuje 
 + 
 +// Konieczne jest dziedziczenie klasy po enable_shared_from_this<>​ 
 + 
 +class WithSharing : public boost::​enable_shared_from_this<​WithSharing>​ { 
 +public: 
 +        boost::​shared_ptr<​WithSharing>​ get_shared() { 
 +                return shared_from_this();​ 
 +        } 
 +}; 
 + 
 +// ========================================================== 
 +// ========================================================== 
 +// ========================================================== 
 + 
 +using namespace std; 
 + 
 +// By uniknąć bardzo długich definicji poniżej 
 +typedef vector< boost::​shared_ptr<​Harry>​ > SharedHarryVector;​ 
 + 
 +// ========================================================== 
 +// Funkcja wyświetla nagłówek tekstowy podkreślony linijką 
 + 
 +void header(const char* label) { 
 +        char* bar = strdup(label);​ 
 +        cout << endl << label << endl; 
 +        memset(bar, ​'=', strlen(bar));​ 
 +        cout << bar << endl; 
 +        free(bar);​ 
 +
 + 
 +// ========================================================== 
 +// ========================================================== 
 + 
 +// Funkcja jest wywoływana,​ ale szkodliwy fragment jest wykomentowany 
 +void play_dirty_harry() { 
 +        header("​Dirty Harry - czego ze wskaznikami robic nie wolno"​);​ 
 + 
 +        Harry* tmp_harry;​ 
 +        boost::​scoped_ptr<​Harry>​ harry(tmp_harry = new Harry("​Simple Class Harry"​));​ 
 + 
 +        //​boost::​scoped_ptr<​Harry>​ harry2(tmp_harry);​ 
 +        // Nielegalne - dwa scoped_ptr, każdy z liczbą odwołań = 1 
 +        // Podczas destrukcji dwóch scoped_ptr dochodzi dwa razy do próby destrukcji  
 +        // jednego obiektu klasy Harry. Lepiej przedstawi to shared_ptr, który pojawi  
 +        // się poniżej 
 + 
 +        //​boost::​scoped_ptr<​Harry>​ harry_b(harry);​ 
 +        // Kopiowanie scoped_ptr jest zakazane (konst. kopiujący w sekcji private) 
 +        //​boost::​scoped_ptr<​Harry>​ harry_c; 
 +        //harry_c = harry; 
 +        // Analogiczna uwaga dotyczy operatora przypisania 
 + 
 +
 + 
 +void play_nice_harry() { 
 +        header("​play_nice_harry - scoped_ptr jak zmienna automatyczna"​);​ 
 +        // Jakieś tam zadania 
 +        // ... 
 + 
 +        // Tutaj proste zastosowanie - scoped_ptr zachowuje się jak zmienna  
 +        // automatyczna. Po wyjściu poza zasięg, scoped_ptr niszczy siebie, a  
 +        // wcześniej związany z nim obiekt. 
 +        // 
 +        // Stąd nazwa - scoped - czyli dot. zasięgu. 
 +        // Nawiązuje to do pomysłu "​resource acquisition is initialization"​. Zasoby  
 +        // są zajmowane w momencie inicjalizacji i, co ważniejsze,​ zwalniane podczas  
 +        // "​odinicjowania",​ czyli destrukcji po wyjściu poza zasięg. 
 + 
 +        boost::​scoped_ptr<​Harry>​ harry3(new Harry("​Harry3"​));​ 
 +        harry3->​hello();​ 
 + 
 +        Harry harry4("​Harry4"​);​ 
 +        harry4.hello();​ 
 + 
 +
 + 
 +void play_nice_harry3() { 
 +        // Jednak nie zawsze wystarcza nam zmienna automatyczna. Ciekawsze jest  
 +        // dynamiczne powoływanie obiektów do życia operatorem "​new"​. 
 + 
 +        header("​play_nice_harry3 - operator \"​new\"​ bez potrzeby wywolania delete"​);​ 
 +        boost::​scoped_ptr<​Harry>​ harry7; 
 + 
 +        // 
 +        // Coś tam do roboty... 
 +        bool needHarry = true; 
 +        // Coś tam do roboty... 
 +        // 
 + 
 +        if(needHarry) 
 +                harry7.reset(new Harry("​Harry7"​));​ 
 + 
 +        // 
 +        // Coś tam do roboty... 
 +        // 
 + 
 +        if(harry7) { 
 +                printf("​-- Stwierdzlismy,​ ze harry7 sie przyda - wykonajmy na nim operacje\n"​);​ 
 +                // Operacje na Harrym... 
 +        } 
 + 
 +        // Normalnie w tym miejscu przydałoby się wywołanie delete na zwykłym  
 +        // wskaźniku. Ponieważ jednak nasz inteligenty wskaźnik jest zmienną  
 +        // automatyczną,​ sam usunie siebie i skojarzony obiekt 
 +
 + 
 +void comfort_test() throw(exception) { 
 +        header("​Comfort test - shared_ptr jak zm. auto.; auto. usuwanie, gdy rzucany jest 
 +wyjatek"​);​ 
 +        boost::​shared_ptr<​Harry>​ h1; 
 +        boost::​shared_ptr<​Harry>​ h2; 
 + 
 +        // Coś tam... 
 + 
 +        // Potrzebujemy Harry'​ego 
 +        h1.reset(new Harry("​Potter"​));​ 
 +        h2.reset(new Harry("​Callahan"​));​ 
 +        cout << "​Callahan count: " << h2.use_count() << endl; 
 +        h1 = h2; 
 +        cout << "​Callahan zjadl Pottera, count: " << h2.use_count() << endl; 
 +        cout << "h1: "; 
 +                h1->​hello();​ 
 +        cout << "h2: "; 
 +                h2->​hello();​ 
 + 
 +        // Go ahead, make my day. 
 +        //   ​Rzucamy wyjątek 
 +        cout << "​Throwing an exception .44" << endl; 
 +        throw exception();​ 
 +
 + 
 +// Prezentacja,​ jak zachowują się intrusive_ptr 
 +void test_intrusive_ptr() { 
 +        header("​test_intrusive_ptr"​);​ 
 +        boost::​intrusive_ptr<​Intruded>​ i1(new Intruded);​ 
 +
 + 
 +// Ciekawostka związana z shared_ptr 
 +// Różnica, między tym, co deklarujemy jako klasę dla szablonu shared_ptr, a  
 +// klasą parametru przekazywanego w konstruktorze. Jakie nieoczywiste zdarzenie  
 +// może wystąpić, gdy destruktory klas są niewirtualne. 
 + 
 +void non_virt_diffs() { 
 +        header("​Niewirtualny destruktor. Roznice miedzy zwyklym wskaznikiem a shared_ptr"​);​ 
 +        // Destructor nie jest wirtualny, stąd Betty nie jest niszczona 
 +        { 
 +                cout << "​Zwykly Harry-wskaznik na Betty" << endl; 
 +                Harry *hb = new Betty; 
 +                delete hb; 
 +        } 
 +         
 +        // Nieco inaczej sprawa się przestawia dla shared_ptr 
 +        { 
 +                cout << endl << "​Betty-wskaznik na Betty w Harry-szablonie"​ << endl; 
 +                boost::​shared_ptr<​Harry>​ b1(new Betty); 
 +                // shared_ptr pamięta rzeczywisty typ wskaźnika przekazywanego w  
 +                // parametrze. W związku z tym używa destruktora dla tego typu (Betty)  
 +                // zamiast typu deklarowanego w szablonie (Harry) 
 +                //  > przykładowa implementacja mechanizmu:​ 
 +                //  > http://​wodny.org/​download/​smart_ptr/​template_memory.cpp 
 +        } 
 +         
 +        { 
 +                cout << endl << "​Harry-wskaznik na Betty w Harry-szablonie"​ << endl; 
 +                Harry *b3 = new Betty; 
 +                boost::​shared_ptr<​Harry>​ b2(b3); 
 +                // Tutaj shared_ptr nie ma okazji poznać prawdziwego typu obiektu. ​  
 +                // Traktuje go jak Harry'​ego. Dla poprawnego działania, tu destruktor już  
 +                // musi być wirtualny. 
 +        } 
 + 
 +
 + 
 +void play_scoped_array() { 
 +        // Prosty przykład, że inteligentne wskaźniki z dopiskiem _array służą do  
 +        // kojarzenia ich z tablicami. Nie można by tu użyć scoped_ptr. Jest to  
 +        // związane z obostrzeniem,​ że delete stosujemy dla pojedynczego obiektu,  
 +        // delete[] dla tablic. Inteligenty wskaźnik nie posiadając informacji o  
 +        // naturze przekazanego wskaźnika źle zarządzałby pamięcią. 
 +        header("​Zabawy ze scoped_array"​);​ 
 +        boost::​scoped_array<​Harry>​ harry_a1(new Harry[3]);​ 
 +
 + 
 +void general_use() { 
 +        header("​Ogolny sposob uzycia shared_ptr"​);​ 
 + 
 +        Harry *hp1 = NULL; 
 +        boost::​shared_ptr<​Harry>​ harry_sp1(hp1 = new Harry("​Shared Harry1"​));​ 
 +        cout << "​harry_sp1.use_count:​ " << harry_sp1.use_count() << endl; 
 +        //​boost::​shared_ptr<​Harry>​ harry_sp2(hp1);​ 
 +        // Taka konstrukcja spowoduje błąd. Dwa shared_ptr będą próbowały usunąć dwa  
 +        // razy ten sam obiekt podczas własnej destrukcji. 
 +        // 
 +        // Istotne jest, by zauważyć, że shared_ptr nie ma jakiejś ukrytej tablicy  
 +        // asocjacyjnej (trzymającej się np. wzorca Singleton), która pozwalałaby mu  
 +        // stwierdzać,​ którymi wskaźnikami już się opiekuje. 
 +        // Poinformowanie o tym, że kolejny shared_ptr chce również odnosić się do  
 +        // danego zwykłego wskaźnika następuje przez wykonanie konstruktora  
 +        // kopiującego (opcjonalnie operatora przypisania). Od tej pory każdy z  
 +        // shared_ptr ustawi ilość odwołań na 2 i przy destrukcji jednego z nich,  
 +        // drugi inteligenty wskaźnik dowie się o tym zdarzeniu i zdekrementuje  
 +        // własny licznik odwołań 
 +        // (Mowa jest tu o logice działania, nie rzeczywistej implementacji  
 +        // inteligentnego wskaźnika). 
 +        cout << "Czas, by podzielic sie zasobem"​ << endl; 
 +        boost::​shared_ptr<​Harry>​ harry_sp2(harry_sp1);​ 
 +        boost::​shared_ptr<​Harry>​ harry_sp3;​ 
 +        harry_sp3 = harry_sp2;​ 
 +        cout << "​harry_sp1.use_count:​ " << harry_sp1.use_count() << endl; 
 +        cout << "​harry_sp2.use_count:​ " << harry_sp2.use_count() << endl; 
 +        cout << "​harry_sp3.use_count:​ " << harry_sp3.use_count() << endl; 
 + 
 +
 + 
 +SharedHarryVector* get_harries() { 
 +        // Shared_ptr a kontenery 
 +        // (scoped_ptr nie może zostać użyty do takich zastosowań - nie da się  
 +        // skopiować kontenerowi,​ poza tym jego przeznaczenie jest inne) 
 +        header("​Wektor (vector) z Harrych - uzycie shared_ptr w kontenerach STL"​);​ 
 + 
 +        SharedHarryVector *vect = new SharedHarryVector();​ 
 +        boost::​shared_ptr<​Harry>​ h; 
 +        for(int i = 0; i < 4; ++i) { 
 +                h.reset(new Harry("​Vector Harry"​));​ 
 +                cout << "Ilosc Harry'​ego przed wlozeniem do wektora: " << h.use_count() << endl; 
 +                vect->​push_back(h);​ 
 +                cout << "Po wlozeniu: " << h.use_count() << endl; 
 +        } 
 +        return vect; 
 +
 + 
 +void stl_container() { 
 +        // W nawiązaniu do powyższej funkcji 
 +        boost::​shared_ptr<​ SharedHarryVector > harry_vector(get_harries());​ 
 +        cout << "​Liczność jednego z wektorowych Harrych: " << 
 +harry_vector->​front().use_count() << endl << endl; 
 +
 + 
 +void no_cycle() { 
 +        header("​Bez cyklu"​);​ 
 +        // Bez cyklu 
 +        boost::​shared_ptr<​RingNode>​ R3(new RingNode("​RingNode3",​ 
 +boost::​shared_ptr<​RingNode>​((RingNode*)NULL)));​ 
 +        boost::​shared_ptr<​RingNode>​ R4(new RingNode("​RingNode4",​ 
 +boost::​shared_ptr<​RingNode>​(R3)));​ 
 +        cout << "R3 (" << R4->​get_name() << ") with count " << R3.use_count() << endl; 
 +        cout << "R4 (" << R4->​get_name() << ") with count " << R4.use_count() << " 
 +connected to " << R4->​get_node()->​get_name() << endl; 
 +        // Wszystkie węzły ulegną zniszczeniu jak powinny 
 +
 + 
 +void shared_cycle() { 
 +        header("​Cykl na shared_ptr"​);​ 
 +        // Większy cykl, choć uzyskany tylko pośrednio, powoduje, że węzły nie  
 +        // zostaną usunięte, ponieważ ilość odwołań w shared_ptr nie spadnie do zera 
 +        boost::​shared_ptr<​RingNode>​ R7(new RingNode("​RingNode7",​ 
 +boost::​shared_ptr<​RingNode>​((RingNode*)NULL)));​ 
 +        boost::​shared_ptr<​RingNode>​ R8(new RingNode("​RingNode8",​ 
 +boost::​shared_ptr<​RingNode>​(R7)));​ 
 +        boost::​shared_ptr<​RingNode>​ R9(new RingNode("​RingNode9",​ 
 +boost::​shared_ptr<​RingNode>​(R8)));​ 
 +        R7->​connect(R9);​ 
 +        cout << "R7 (" << R7->​get_name() << ") with count " << R7.use_count() << " 
 +connected to " << R7->​get_node()->​get_name() << endl; 
 +        cout << "R8 (" << R8->​get_name() << ") with count " << R8.use_count() << " 
 +connected to " << R8->​get_node()->​get_name() << endl; 
 +        cout << "R9 (" << R9->​get_name() << ") with count " << R9.use_count() << " 
 +connected to " << R9->​get_node()->​get_name() << endl; 
 + 
 +        /* 
 +    R7-->"​R7"<​--------node--------. 
 +           ​| ​                     | 
 +           ​*--node-->"​R8"<​--R8 ​   | 
 +                       ​| ​         | 
 +                       ​*--node-->"​R9"<​--R9 
 +        */ 
 +
 + 
 +void weak_cycle() { 
 +        header("​Cykl na weak_ptr"​);​ 
 +        // "​Słaby"​ cykl oparty o weak_ptr 
 +        boost::​shared_ptr<​WeakRingNode>​ R5(new WeakRingNode("​WeakRingNode5",​ 
 +boost::​shared_ptr<​WeakRingNode>​((WeakRingNode*)NULL)));​ 
 +        boost::​shared_ptr<​WeakRingNode>​ R6(new WeakRingNode("​WeakRingNode6",​ 
 +boost::​shared_ptr<​WeakRingNode>​(R5)));​ 
 +        R5->​connect(R6);​ 
 +        boost::​weak_ptr<​WeakRingNode>​ Wtmp1(R5);​ 
 +        boost::​weak_ptr<​WeakRingNode>​ Wtmp2(R6);​ 
 +        // Jak można zauważyć, weak_ptr nie zwiększa licznika odwołań do obiektu,  
 +        // którego dotyczy, ani nie usuwa obiektu, gdy wielkość ta spadnie do zera.   
 +        // Obiekt, do którego się odwołuje może zostać usunięty "bez jego wiedzy"​. ​  
 +        // Dlatego właśnie współpracuje z shared_ptr. 
 +        cout << "R5 (" << R5->​get_name() << ") with count " << R5.use_count() << " 
 +connected to " << R5->​get_node()->​get_name() << endl; 
 +        cout << "R6 (" << R6->​get_name() << ") with count " << R6.use_count() << " 
 +connected to " << R6->​get_node()->​get_name() << endl; 
 +        // Poprzez funkcję weak_ptr.lock(),​ która użyta jest w get_node(), weak_ptr  
 +        // gwarantuje nam, że zostanie wykonana dodatkowa kopia, a shared_ptr zajmie  
 +        // się zwiększeniem licznika odwołań, by obiekt nie zniknął podczas  
 +        // wykonywania na nim operacji. 
 +        // Jeśli obiekt zdążył zniknąć już wcześniej, podczas tworzenia shared_ptr z  
 +        // weak_ptr dostaniemy wyjątek bad_weak_ptr. 
 +
 + 
 +void shared_and_weak() { 
 +        header("​Relacja miedzy shared_ptr i weak_ptr"​);​ 
 + 
 +        cout << "​Oryginalny shared_ptr:"​ << endl; 
 +        boost::​shared_ptr<​Harry>​ shared1(new Harry); 
 +        cout << "​shared1.count:​ " << shared1.use_count() << endl; 
 + 
 +        cout << "​weak_ptr z shared_ptr:"​ << endl; 
 +        boost::​weak_ptr<​Harry>​ weak1(shared1);​ 
 +        cout << "​shared1.count:​ " << shared1.use_count() << endl; 
 +        cout << "​weak1.count ​ : " << weak1.use_count() << endl; 
 + 
 +        cout << "​shared_ptr z weak_ptr (z shared_ptr)"​ << endl; 
 +        boost::​shared_ptr<​Harry>​ shared2(weak1);​ 
 +        cout << "​shared1.count:​ " << shared1.use_count() << endl; 
 +        cout << "​weak1.count ​ : " << weak1.use_count() << endl; 
 +        cout << "​shared2.count:​ " << shared2.use_count() << endl; 
 +
 + 
 +void with_sharing_test(WithSharing&​ ws) { 
 +        header("​Test enable_shared_from_this<>"​);​ 
 + 
 +        boost::​shared_ptr<​WithSharing>​ ws_a(ws.get_shared());​ 
 +        cout << "Drugi udzial, use_count: " << ws_a.use_count() << endl; 
 +        /*  . 
 +         * /|\ 
 +         ​* ​ | 
 +         * ------------------------------------------------- 
 +         * dwa niezależne fragmenty kodu, np. dwa wątki 
 +         * ------------------------------------------------- 
 +         ​* ​ | 
 +         * \|/ 
 +         ​* ​ ' 
 +         */ 
 +        boost::​shared_ptr<​WithSharing>​ ws_b(ws.get_shared());​ 
 +        cout << "​Trzeci udzial, use_count: " << ws_b.use_count() << endl; 
 + 
 +
 + 
 +void auto_ptr_demo() { 
 +        header("​auto_ptr - przy boost maly sens stosowania"​);​ 
 +        /* 
 +         * 
 +http://​gcc.gnu.org/​onlinedocs/​libstdc++/​libstdc++-html-USERS-4.0/​classstd_1_1auto__ptr.html 
 +         * 
 +         * "​auto_ptr does not meet the CopyConstructible and Assignable 
 +         * requirements for Standard Library container elements and thus 
 +         * instantiating a Standard Library container with an auto_ptr results in  
 +         * undefined behavior."​ 
 +         * 
 +         * Reasumując - auto_ptr ciekawy nie jest. Potrafi tylko oddawać powiązanie z  
 +         * obiektem, natomiast nie potrafi się nim dzielić. Zastosowanie w  
 +         * kontenerach nie jest możliwe. 
 +         */ 
 + 
 +        auto_ptr<​Harry>​ a1(new Harry); 
 +        cout << "NEW. " << a1.get() << endl; 
 +        auto_ptr<​Harry>​ a2(a1); 
 +        cout << "1st transfer, source: " << a1.get() << endl; 
 +        cout << "1st transfer, dest. : " << a2.get() << endl; 
 +        auto_ptr<​Harry>​ a3 = a2; 
 +        cout << "2nd transfer, source: " << a2.get() << endl; 
 +        cout << "2nd transfer, dest. : " << a3.get() << endl; 
 +
 + 
 +// ========================================================== 
 +// ========================================================== 
 +// ========================================================== 
 + 
 +int main(int argc, char** argv) { 
 +        // ========================================================== 
 +        // Zestaw tego, czego robić nie wolno ze scoped_ptr 
 +        play_dirty_harry();​ 
 + 
 +        // shared_ptr 
 +        general_use();​ 
 + 
 +        // Mniej interesujące 
 +        play_nice_harry();​ 
 +        // Bardziej interesujące 
 +        play_nice_harry3();​ 
 +         
 +        // scoped_array zamiast scoped_ptr - właściwe delete, konkretnie delete[] 
 +        play_scoped_array();​ 
 + 
 +        // Niewirtualny destruktor. Różnice między zwykłym wskaźnikiem a shared_ptr 
 +        non_virt_diffs();​ 
 + 
 +        // ========================================================== 
 +        // Kontener STL 
 +        stl_container();​ 
 + 
 +        // ========================================================== 
 +        // Shared vs Weak a cykle 
 + 
 +        no_cycle();​ 
 +        shared_cycle();​ 
 +        weak_cycle();​ 
 +        shared_and_weak();​ 
 + 
 +        // ========================================================== 
 +        //  GŁÓWNY POWÓD UŻYWANIA SMART_PTRów 
 +        //    komfort operatora "​new"​ 
 +        //    z bezpieczeństwem zmiennych automatycznych 
 +        // ========================================================== 
 +        try { 
 +                comfort_test();​ 
 +        } catch (...) { 
 +                cout << "​Caught!"​ << endl; 
 +        } 
 + 
 +        // ========================================================== 
 +        // Test enable_shared_from_this<>​ 
 +        boost::​shared_ptr<​WithSharing>​ ws(new WithSharing);​ 
 +        with_sharing_test(*ws);​ 
 + 
 +        // ========================================================== 
 +        // std::​auto_ptr 
 +        auto_ptr_demo();​ 
 + 
 +        // ========================================================== 
 +        // Intrusive test 
 +        test_intrusive_ptr();​ 
 + 
 +        return 0; 
 +
 + 
 + 
 + 
 +</​code>​
smart_ptr.1208301393.txt.gz · ostatnio zmienione: 2008/04/16 01:16 przez wodny