Narzędzia użytkownika

Narzędzia witryny


smart_ptr

smart_ptr_latin2.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;
}
smart_ptr.txt · ostatnio zmienione: 2008/10/23 11:03 przez rnowak2