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

Both sides previous revision Previous revision
Next revision
Previous revision
smart_ptr [2008/04/16 01:25]
wodny utworzono
smart_ptr [2008/10/23 11:03] (aktualna)
rnowak2
Linia 1: Linia 1:
 +{{smart_ptr_latin2.cpp|}}
 <code 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>​ </​code>​
smart_ptr.1208301949.txt.gz · ostatnio zmienione: 2008/04/16 01:25 przez wodny