Różnice między wybraną wersją a wersją aktualną.
| Both sides previous revision Previous revision | |||
|
smart_ptr [2008/04/16 01:48] wodny |
smart_ptr [2008/10/23 11:03] (aktualna) rnowak2 |
||
|---|---|---|---|
| Linia 1: | Linia 1: | ||
| - | {{libs:smart_ptr:smart_ptr_iso.cpp|}} | + | {{smart_ptr_latin2.cpp|}} |
| <code cpp> | <code cpp> | ||
| - | /* | + | * |
| * Autor: Marcin Szewczyk, 198370 | * Autor: Marcin Szewczyk, 198370 | ||
| * | * | ||
| Linia 24: | Linia 24: | ||
| * nie został opisany typ shared_array, ponieważ nie wnosi nic nowego do | * nie został opisany typ shared_array, ponieważ nie wnosi nic nowego do | ||
| * omawianych tu zagadnień | * 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 | ||
| */ | */ | ||
| Linia 42: | Linia 63: | ||
| class Harry { | class Harry { | ||
| - | public: | + | public: |
| - | Harry(const char* = NULL); | + | Harry(const char* = NULL); |
| - | ~Harry(); | + | ~Harry(); |
| - | void hello(); | + | void hello(); |
| - | private: | + | private: |
| - | char *name; | + | char *name; |
| }; | }; | ||
| class Betty : public Harry { | class Betty : public Harry { | ||
| - | public: | + | public: |
| - | Betty(); | + | Betty(); |
| - | ~Betty(); | + | ~Betty(); |
| }; | }; | ||
| Linia 61: | Linia 82: | ||
| Harry::Harry(const char *name_) { | Harry::Harry(const char *name_) { | ||
| - | name = name_ ? strdup(name_) : NULL; | + | name = name_ ? strdup(name_) : NULL; |
| - | printf("-- Constructing Harry (%s)\n", name); | + | printf("-- Constructing Harry (%s)\n", name); |
| } | } | ||
| Harry::~Harry() { | Harry::~Harry() { | ||
| - | printf("-- Deconstructing Harry (%s)\n", name); | + | printf("-- Deconstructing Harry (%s)\n", name); |
| + | free(name); | ||
| } | } | ||
| void Harry::hello() { | void Harry::hello() { | ||
| - | printf("-- Harry \"%s\" says hello\n", name); | + | printf("-- Harry \"%s\" says hello\n", name); |
| } | } | ||
| Linia 76: | Linia 98: | ||
| Betty::Betty() { | Betty::Betty() { | ||
| - | printf("---- Constructing Betty\n"); | + | printf("---- Constructing Betty\n"); |
| } | } | ||
| Betty::~Betty() { | Betty::~Betty() { | ||
| - | printf("---- Deconstructing Betty\n"); | + | printf("---- Deconstructing Betty\n"); |
| } | } | ||
| Linia 90: | Linia 112: | ||
| class RingNode { | class RingNode { | ||
| - | public: | + | public: |
| - | RingNode(const char*, const boost::shared_ptr<RingNode>&); | + | RingNode(const char*, const boost::shared_ptr<RingNode>&); |
| - | ~RingNode(); | + | ~RingNode(); |
| - | void connect(const boost::shared_ptr<RingNode>&); | + | void connect(const boost::shared_ptr<RingNode>&); |
| - | const char* get_name(); | + | const char* get_name(); |
| - | const boost::shared_ptr<RingNode>& get_node(); | + | const boost::shared_ptr<RingNode>& get_node(); |
| - | private: | + | private: |
| - | boost::shared_ptr<RingNode> node; | + | boost::shared_ptr<RingNode> node; |
| - | char* name; | + | char* name; |
| }; | }; | ||
| - | RingNode::RingNode(const char* name_, const boost::shared_ptr<RingNode>& node_) : node(node_){ | + | RingNode::RingNode(const char* name_, const boost::shared_ptr<RingNode>& node_) : |
| - | name = name_ ? strdup(name_) : NULL; | + | node(node_) { |
| - | printf("++ Constructing RingNode (%s)\n", name); | + | name = name_ ? strdup(name_) : NULL; |
| + | printf("++ Constructing RingNode (%s)\n", name); | ||
| } | } | ||
| RingNode::~RingNode() { | RingNode::~RingNode() { | ||
| - | printf("++ Deconstructing RingNode (%s)\n", name); | + | printf("++ Deconstructing RingNode (%s)\n", name); |
| + | free(name); | ||
| } | } | ||
| void RingNode::connect(const boost::shared_ptr<RingNode>& node_) { | void RingNode::connect(const boost::shared_ptr<RingNode>& node_) { | ||
| - | node = node_; | + | node = node_; |
| } | } | ||
| const char* RingNode::get_name() { | const char* RingNode::get_name() { | ||
| - | return name; | + | return name; |
| } | } | ||
| const boost::shared_ptr<RingNode>& RingNode::get_node() { | const boost::shared_ptr<RingNode>& RingNode::get_node() { | ||
| - | return node; | + | return node; |
| } | } | ||
| Linia 126: | Linia 150: | ||
| class WeakRingNode { | class WeakRingNode { | ||
| - | public: | + | public: |
| - | WeakRingNode(const char*, const boost::shared_ptr<WeakRingNode>&); | + | WeakRingNode(const char*, const boost::shared_ptr<WeakRingNode>&); |
| - | ~WeakRingNode(); | + | ~WeakRingNode(); |
| - | void connect(const boost::shared_ptr<WeakRingNode>&); | + | void connect(const boost::shared_ptr<WeakRingNode>&); |
| - | const char* get_name(); | + | const char* get_name(); |
| - | const boost::shared_ptr<WeakRingNode> get_node(); | + | const boost::shared_ptr<WeakRingNode> get_node(); |
| - | private: | + | private: |
| - | boost::weak_ptr<WeakRingNode> node; | + | boost::weak_ptr<WeakRingNode> node; |
| - | char* name; | + | char* name; |
| }; | }; | ||
| - | WeakRingNode::WeakRingNode(const char* name_, const boost::shared_ptr<WeakRingNode>& node_) : node(node_) { | + | WeakRingNode::WeakRingNode(const char* name_, const boost::shared_ptr<WeakRingNode>& |
| - | name = name_ ? strdup(name_) : NULL; | + | node_) : node(node_) { |
| - | printf("++ Constructing RingNode (%s)\n", name); | + | name = name_ ? strdup(name_) : NULL; |
| + | printf("++ Constructing RingNode (%s)\n", name); | ||
| } | } | ||
| WeakRingNode::~WeakRingNode() { | WeakRingNode::~WeakRingNode() { | ||
| - | printf("++ Deconstructing RingNode (%s)\n", name); | + | printf("++ Deconstructing RingNode (%s)\n", name); |
| + | free(name); | ||
| } | } | ||
| void WeakRingNode::connect(const boost::shared_ptr<WeakRingNode>& node_) { | void WeakRingNode::connect(const boost::shared_ptr<WeakRingNode>& node_) { | ||
| - | node = node_; | + | node = node_; |
| } | } | ||
| const char* WeakRingNode::get_name() { | const char* WeakRingNode::get_name() { | ||
| - | return name; | + | return name; |
| } | } | ||
| const boost::shared_ptr<WeakRingNode> WeakRingNode::get_node() { | const boost::shared_ptr<WeakRingNode> WeakRingNode::get_node() { | ||
| - | return node.lock(); | + | return node.lock(); |
| } | } | ||
| Linia 165: | Linia 191: | ||
| class Intruded { | class Intruded { | ||
| - | public: | + | public: |
| - | Intruded(); | + | Intruded(); |
| - | ~Intruded(); | + | ~Intruded(); |
| - | private: | + | private: |
| - | int counter; | + | int counter; |
| - | friend void intrusive_ptr_add_ref(Intruded *const); | + | friend void intrusive_ptr_add_ref(Intruded *const); |
| - | friend void intrusive_ptr_release(Intruded *const); | + | friend void intrusive_ptr_release(Intruded *const); |
| }; | }; | ||
| Linia 181: | Linia 207: | ||
| Intruded::Intruded() : counter(0) { | Intruded::Intruded() : counter(0) { | ||
| - | printf("%% Creating Intruded\n"); | + | printf("%% Creating Intruded\n"); |
| } | } | ||
| Intruded::~Intruded() { | Intruded::~Intruded() { | ||
| - | printf("%% Destroying Intruded\n"); | + | printf("%% Destroying Intruded\n"); |
| } | } | ||
| Linia 194: | Linia 220: | ||
| void intrusive_ptr_add_ref(Intruded *const p) { | void intrusive_ptr_add_ref(Intruded *const p) { | ||
| - | printf("%% Added. Now: %d\n", ++(p->counter)); | + | printf("%% Added. Now: %d\n", ++(p->counter)); |
| } | } | ||
| void intrusive_ptr_release(Intruded *const p) { | void intrusive_ptr_release(Intruded *const p) { | ||
| - | printf("%% Removed. Now: %d\n", --(p->counter)); | + | printf("%% Removed. Now: %d\n", --(p->counter)); |
| - | if(!p->counter) { | + | if(!p->counter) { |
| - | printf("%% Deleting Intruded because of count == 0...\n"); | + | printf("%% Deleting Intruded because of count == 0...\n"); |
| - | delete p; | + | delete p; |
| - | } | + | } |
| } | } | ||
| Linia 214: | Linia 240: | ||
| class WithSharing : public boost::enable_shared_from_this<WithSharing> { | class WithSharing : public boost::enable_shared_from_this<WithSharing> { | ||
| public: | public: | ||
| - | boost::shared_ptr<WithSharing> get_shared() { | + | boost::shared_ptr<WithSharing> get_shared() { |
| - | return shared_from_this(); | + | return shared_from_this(); |
| - | } | + | } |
| }; | }; | ||
| Linia 232: | Linia 258: | ||
| void header(const char* label) { | void header(const char* label) { | ||
| - | char* bar = strdup(label); | + | char* bar = strdup(label); |
| - | memset(bar, '=', strlen(bar)); | + | cout << endl << label << endl; |
| - | cout << endl << label << endl << bar << endl; | + | memset(bar, '=', strlen(bar)); |
| + | cout << bar << endl; | ||
| + | free(bar); | ||
| } | } | ||
| Linia 242: | Linia 270: | ||
| // Funkcja jest wywoływana, ale szkodliwy fragment jest wykomentowany | // Funkcja jest wywoływana, ale szkodliwy fragment jest wykomentowany | ||
| void play_dirty_harry() { | void play_dirty_harry() { | ||
| - | header("Dirty Harry - czego ze wskaznikami robic nie wolno"); | + | header("Dirty Harry - czego ze wskaznikami robic nie wolno"); |
| - | Harry* tmp_harry; | + | Harry* tmp_harry; |
| - | boost::scoped_ptr<Harry> harry(tmp_harry = new Harry("Simple Class Harry")); | + | boost::scoped_ptr<Harry> harry(tmp_harry = new Harry("Simple Class Harry")); |
| - | //boost::scoped_ptr<Harry> harry2(tmp_harry); | + | //boost::scoped_ptr<Harry> harry2(tmp_harry); |
| - | // Nielegalne - dwa scoped_ptr, każdy z liczbą odwołań = 1 | + | // Nielegalne - dwa scoped_ptr, każdy z liczbą odwołań = 1 |
| - | // Podczas destrukcji dwóch scoped_ptr dochodzi dwa razy do próby destrukcji | + | // 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 | + | // jednego obiektu klasy Harry. Lepiej przedstawi to shared_ptr, który pojawi |
| - | // się poniżej | + | // się poniżej |
| - | //boost::scoped_ptr<Harry> harry_b(harry); | + | //boost::scoped_ptr<Harry> harry_b(harry); |
| - | // Kopiowanie scoped_ptr jest zakazane (konst. kopiujący w sekcji private) | + | // Kopiowanie scoped_ptr jest zakazane (konst. kopiujący w sekcji private) |
| - | //boost::scoped_ptr<Harry> harry_c; | + | //boost::scoped_ptr<Harry> harry_c; |
| - | //harry_c = harry; | + | //harry_c = harry; |
| - | // Analogiczna uwaga dotyczy operatora przypisania | + | // Analogiczna uwaga dotyczy operatora przypisania |
| } | } | ||
| void play_nice_harry() { | void play_nice_harry() { | ||
| - | header("play_nice_harry - scoped_ptr jak zmienna automatyczna"); | + | header("play_nice_harry - scoped_ptr jak zmienna automatyczna"); |
| - | // Jakieś tam zadania | + | // Jakieś tam zadania |
| - | // ... | + | // ... |
| - | // Tutaj proste zastosowanie - scoped_ptr zachowuje się jak zmienna | + | // Tutaj proste zastosowanie - scoped_ptr zachowuje się jak zmienna |
| - | // automatyczna. Po wyjściu poza zasięg, scoped_ptr niszczy siebie, a | + | // automatyczna. Po wyjściu poza zasięg, scoped_ptr niszczy siebie, a |
| - | // wcześniej związany z nim obiekt. | + | // wcześniej związany z nim obiekt. |
| - | // | + | // |
| - | // Stąd nazwa - scoped - czyli dot. zasięgu. | + | // Stąd nazwa - scoped - czyli dot. zasięgu. |
| - | // Nawiązuje to do pomysłu "resource acquisition is initialization". Zasoby | + | // Nawiązuje to do pomysłu "resource acquisition is initialization". Zasoby |
| - | // są zajmowane w momencie inicjalizacji i, co ważniejsze, zwalniane podczas | + | // są zajmowane w momencie inicjalizacji i, co ważniejsze, zwalniane podczas |
| - | // "odinicjowania", czyli destrukcji po wyjściu poza zasięg. | + | // "odinicjowania", czyli destrukcji po wyjściu poza zasięg. |
| - | boost::scoped_ptr<Harry> harry3(new Harry("Harry3")); | + | boost::scoped_ptr<Harry> harry3(new Harry("Harry3")); |
| - | harry3->hello(); | + | harry3->hello(); |
| - | Harry harry4("Harry4"); | + | Harry harry4("Harry4"); |
| - | harry4.hello(); | + | harry4.hello(); |
| } | } | ||
| void play_nice_harry3() { | void play_nice_harry3() { | ||
| - | // Jednak nie zawsze wystarcza nam zmienna automatyczna. Ciekawsze jest | + | // Jednak nie zawsze wystarcza nam zmienna automatyczna. Ciekawsze jest |
| - | // dynamiczne powoływanie obiektów do życia operatorem "new". | + | // dynamiczne powoływanie obiektów do życia operatorem "new". |
| - | header("play_nice_harry3 - operator \"new\" bez potrzeby wywolania delete"); | + | header("play_nice_harry3 - operator \"new\" bez potrzeby wywolania delete"); |
| - | boost::scoped_ptr<Harry> harry7; | + | boost::scoped_ptr<Harry> harry7; |
| - | // | + | // |
| - | // Coś tam do roboty... | + | // Coś tam do roboty... |
| - | bool needHarry = true; | + | bool needHarry = true; |
| - | // Coś tam do roboty... | + | // Coś tam do roboty... |
| - | // | + | // |
| - | if(needHarry) | + | if(needHarry) |
| + | harry7.reset(new Harry("Harry7")); | ||
| - | harry7.reset(new Harry("Harry7")); | + | // |
| + | // Coś tam do roboty... | ||
| + | // | ||
| - | // | + | if(harry7) { |
| - | // Coś tam do roboty... | + | printf("-- Stwierdzlismy, ze harry7 sie przyda - wykonajmy na nim operacje\n"); |
| - | // | + | // Operacje na Harrym... |
| + | } | ||
| - | if(harry7) { | + | // Normalnie w tym miejscu przydałoby się wywołanie delete na zwykłym |
| - | printf("-- Stwierdzlismy, ze harry7 sie przyda - wykonajmy na nim operacje\n"); | + | // wskaźniku. Ponieważ jednak nasz inteligenty wskaźnik jest zmienną |
| - | // Operacje na Harrym... | + | // automatyczną, sam usunie siebie i skojarzony obiekt |
| - | } | + | |
| - | + | ||
| - | // 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) { | void comfort_test() throw(exception) { | ||
| - | header("Comfort test - shared_ptr jak zm. auto.; auto. usuwanie, gdy rzucany jest wyjatek"); | + | header("Comfort test - shared_ptr jak zm. auto.; auto. usuwanie, gdy rzucany jest |
| - | boost::shared_ptr<Harry> h1; | + | wyjatek"); |
| - | boost::shared_ptr<Harry> h2; | + | boost::shared_ptr<Harry> h1; |
| + | boost::shared_ptr<Harry> h2; | ||
| - | // Coś tam... | + | // Coś tam... |
| - | // Potrzebujemy Harry'ego | + | // Potrzebujemy Harry'ego |
| - | h1.reset(new Harry("Potter")); | + | h1.reset(new Harry("Potter")); |
| - | h2.reset(new Harry("Callahan")); | + | h2.reset(new Harry("Callahan")); |
| - | cout << "Callahan count: " << h2.use_count() << endl; | + | cout << "Callahan count: " << h2.use_count() << endl; |
| - | h1 = h2; | + | h1 = h2; |
| - | cout << "Callahan zjadl Pottera, count: " << h2.use_count() << endl; | + | cout << "Callahan zjadl Pottera, count: " << h2.use_count() << endl; |
| - | cout << "h1: "; | + | cout << "h1: "; |
| - | h1->hello(); | + | h1->hello(); |
| - | cout << "h2: "; | + | cout << "h2: "; |
| - | h2->hello(); | + | h2->hello(); |
| - | // Go ahead, make my day. | + | // Go ahead, make my day. |
| - | // Rzucamy wyjątek | + | // Rzucamy wyjątek |
| - | cout << "Throwing an exception .44" << endl; | + | cout << "Throwing an exception .44" << endl; |
| - | throw exception(); | + | throw exception(); |
| } | } | ||
| // Prezentacja, jak zachowują się intrusive_ptr | // Prezentacja, jak zachowują się intrusive_ptr | ||
| void test_intrusive_ptr() { | void test_intrusive_ptr() { | ||
| - | header("test_intrusive_ptr"); | + | header("test_intrusive_ptr"); |
| - | boost::intrusive_ptr<Intruded> i1(new Intruded); | + | boost::intrusive_ptr<Intruded> i1(new Intruded); |
| } | } | ||
| // Ciekawostka związana z shared_ptr | // Ciekawostka związana z shared_ptr | ||
| - | // Różnica, między tym, co deklarujemy jako klasę dla szablony shared_ptr, a | + | // Różnica, między tym, co deklarujemy jako klasę dla szablonu shared_ptr, a |
| // klasą parametru przekazywanego w konstruktorze. Jakie nieoczywiste zdarzenie | // klasą parametru przekazywanego w konstruktorze. Jakie nieoczywiste zdarzenie | ||
| // może wystąpić, gdy destruktory klas są niewirtualne. | // może wystąpić, gdy destruktory klas są niewirtualne. | ||
| void non_virt_diffs() { | void non_virt_diffs() { | ||
| - | header("Niewirtualny destruktor. Roznice miedzy zwyklym wskaznikiem a shared_ptr"); | + | header("Niewirtualny destruktor. Roznice miedzy zwyklym wskaznikiem a shared_ptr"); |
| - | // Destructor nie jest wirtualny, stąd Betty nie jest niszczona | + | // Destructor nie jest wirtualny, stąd Betty nie jest niszczona |
| - | { | + | { |
| - | cout << "Zwykly Harry-wskaznik na Betty" << endl; | + | cout << "Zwykly Harry-wskaznik na Betty" << endl; |
| - | Harry *hb = new Betty; | + | Harry *hb = new Betty; |
| - | delete hb; | + | delete hb; |
| - | } | + | } |
| - | + | ||
| - | // Nieco inaczej sprawa się przestawia dla shared_ptr | + | // Nieco inaczej sprawa się przestawia dla shared_ptr |
| - | { | + | { |
| - | cout << endl << "Betty-wskaznik na Betty w Harry-szablonie" << endl; | + | cout << endl << "Betty-wskaznik na Betty w Harry-szablonie" << endl; |
| - | boost::shared_ptr<Harry> b1(new Betty); | + | boost::shared_ptr<Harry> b1(new Betty); |
| - | // shared_ptr pamięta rzeczywisty typ wskaźnika przekazywanego w | + | // shared_ptr pamięta rzeczywisty typ wskaźnika przekazywanego w |
| - | // parametrze. W związku z tym używa destruktora dla tego typu (Betty) | + | // parametrze. W związku z tym używa destruktora dla tego typu (Betty) |
| - | // zamiast typu deklarowanego w szablonie (Harry) | + | // zamiast typu deklarowanego w szablonie (Harry) |
| - | // > przykładowa implementacja mechanizmu: | + | // > przykładowa implementacja mechanizmu: |
| - | // > http://wodny.org/download/smart_ptr/template_memory.cpp | + | // > http://wodny.org/download/smart_ptr/template_memory.cpp |
| - | } | + | } |
| - | + | ||
| - | { | + | { |
| - | cout << endl << "Harry-wskaznik na Betty w Harry-szablonie" << endl; | + | cout << endl << "Harry-wskaznik na Betty w Harry-szablonie" << endl; |
| - | Harry *b3 = new Betty; | + | Harry *b3 = new Betty; |
| - | boost::shared_ptr<Harry> b2(b3); | + | boost::shared_ptr<Harry> b2(b3); |
| - | // Tutaj shared_ptr nie ma okazji poznać prawdziwego typu obiektu. | + | // Tutaj shared_ptr nie ma okazji poznać prawdziwego typu obiektu. |
| - | // Traktuje go jak Harry'ego. Dla poprawnego działania, tu destruktor już | + | // Traktuje go jak Harry'ego. Dla poprawnego działania, tu destruktor już |
| - | // musi być wirtualny. | + | // musi być wirtualny. |
| - | } | + | } |
| } | } | ||
| void play_scoped_array() { | void play_scoped_array() { | ||
| - | // Prosty przykład, że inteligentne wskaźniki z dopiskiem _array służą do | + | // 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 | + | // 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, | + | // związane z obostrzeniem, że delete stosujemy dla pojedynczego obiektu, |
| - | // delete[] dla tablic. Inteligenty wskaźnik nie posiadając informacji o | + | // delete[] dla tablic. Inteligenty wskaźnik nie posiadając informacji o |
| - | // naturze przekazanego wskaźnika źle zarządzałby pamięcią. | + | // naturze przekazanego wskaźnika źle zarządzałby pamięcią. |
| - | header("Zabawy ze scoped_array"); | + | header("Zabawy ze scoped_array"); |
| - | boost::scoped_array<Harry> harry_a1(new Harry[3]); | + | boost::scoped_array<Harry> harry_a1(new Harry[3]); |
| } | } | ||
| void general_use() { | void general_use() { | ||
| - | header("Ogolny sposob uzycia shared_ptr"); | + | header("Ogolny sposob uzycia shared_ptr"); |
| - | Harry *hp1 = NULL; | + | Harry *hp1 = NULL; |
| - | boost::shared_ptr<Harry> harry_sp1(hp1 = new Harry("Shared Harry1")); | + | boost::shared_ptr<Harry> harry_sp1(hp1 = new Harry("Shared Harry1")); |
| - | cout << "harry_sp1.use_count: " << harry_sp1.use_count() << endl; | + | cout << "harry_sp1.use_count: " << harry_sp1.use_count() << endl; |
| - | //boost::shared_ptr<Harry> harry_sp2(hp1); | + | //boost::shared_ptr<Harry> harry_sp2(hp1); |
| - | // Taka konstrukcja spowoduje błąd. Dwa shared_ptr będą próbowały usunąć dwa | + | // Taka konstrukcja spowoduje błąd. Dwa shared_ptr będą próbowały usunąć dwa |
| - | // razy ten sam obiekt podczas własnej destrukcji. | + | // razy ten sam obiekt podczas własnej destrukcji. |
| - | // | + | // |
| - | // Istotne jest, by zauważyć, że shared_ptr nie ma jakiejś ukrytej tablicy | + | // 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 | + | // asocjacyjnej (trzymającej się np. wzorca Singleton), która pozwalałaby mu |
| - | // stwierdzać, którymi wskaźnikami już się opiekuje. | + | // stwierdzać, którymi wskaźnikami już się opiekuje. |
| - | // Poinformowanie o tym, że kolejny shared_ptr chce również odnosić się do | + | // Poinformowanie o tym, że kolejny shared_ptr chce również odnosić się do |
| - | // danego zwykłego wskaźnika następuje przez wykonanie konstruktora | + | // danego zwykłego wskaźnika następuje przez wykonanie konstruktora |
| - | // kopiującego (opcjonalnie operatora przypisania). Od tej pory każdy z | + | // 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, | + | // 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 | + | // drugi inteligenty wskaźnik dowie się o tym zdarzeniu i zdekrementuje |
| - | // własny licznik odwołań | + | // własny licznik odwołań |
| - | // (Mowa jest tu o logice działania, nie rzeczywistej implementacji | + | // (Mowa jest tu o logice działania, nie rzeczywistej implementacji |
| - | // inteligentnego wskaźnika). | + | // inteligentnego wskaźnika). |
| - | cout << "Czas, by podzielic sie zasobem" << endl; | + | cout << "Czas, by podzielic sie zasobem" << endl; |
| - | boost::shared_ptr<Harry> harry_sp2(harry_sp1); | + | boost::shared_ptr<Harry> harry_sp2(harry_sp1); |
| - | boost::shared_ptr<Harry> harry_sp3; | + | boost::shared_ptr<Harry> harry_sp3; |
| - | harry_sp3 = harry_sp2; | + | harry_sp3 = harry_sp2; |
| - | cout << "harry_sp1.use_count: " << harry_sp1.use_count() << endl; | + | cout << "harry_sp1.use_count: " << harry_sp1.use_count() << endl; |
| - | cout << "harry_sp2.use_count: " << harry_sp2.use_count() << endl; | + | cout << "harry_sp2.use_count: " << harry_sp2.use_count() << endl; |
| - | cout << "harry_sp3.use_count: " << harry_sp3.use_count() << endl; | + | cout << "harry_sp3.use_count: " << harry_sp3.use_count() << endl; |
| } | } | ||
| SharedHarryVector* get_harries() { | SharedHarryVector* get_harries() { | ||
| - | // Shared_ptr a kontenery | + | // Shared_ptr a kontenery |
| - | // (scoped_ptr nie może zostać użyty do takich zastosowań - nie da się | + | // (scoped_ptr nie może zostać użyty do takich zastosowań - nie da się |
| - | // skopiować kontenerowi, poza tym jego przeznaczenie jest inne) | + | // skopiować kontenerowi, poza tym jego przeznaczenie jest inne) |
| - | header("Wektor (vector) z Harrych - uzycie shared_ptr w kontenerach STL"); | + | header("Wektor (vector) z Harrych - uzycie shared_ptr w kontenerach STL"); |
| - | SharedHarryVector *vect = new SharedHarryVector(); | + | SharedHarryVector *vect = new SharedHarryVector(); |
| - | boost::shared_ptr<Harry> h; | + | boost::shared_ptr<Harry> h; |
| - | for(int i = 0; i < 4; ++i) { | + | for(int i = 0; i < 4; ++i) { |
| - | h.reset(new Harry("Vector Harry")); | + | h.reset(new Harry("Vector Harry")); |
| - | cout << "Ilosc Harry'ego przed wlozeniem do wektora: " << h.use_count() << endl; | + | cout << "Ilosc Harry'ego przed wlozeniem do wektora: " << h.use_count() << endl; |
| - | vect->push_back(h); | + | vect->push_back(h); |
| - | cout << "Po wlozeniu: " << h.use_count() << endl; | + | cout << "Po wlozeniu: " << h.use_count() << endl; |
| - | } | + | } |
| - | return vect; | + | return vect; |
| } | } | ||
| void stl_container() { | void stl_container() { | ||
| - | // W nawiązaniu do powyższej funkcji | + | // W nawiązaniu do powyższej funkcji |
| - | boost::shared_ptr< SharedHarryVector > harry_vector(get_harries()); | + | boost::shared_ptr< SharedHarryVector > harry_vector(get_harries()); |
| - | cout << "Liczność jednego z wektorowych Harrych: " << harry_vector->front().use_count() << endl << endl; | + | cout << "Liczność jednego z wektorowych Harrych: " << |
| + | harry_vector->front().use_count() << endl << endl; | ||
| } | } | ||
| void no_cycle() { | void no_cycle() { | ||
| - | header("Bez cyklu"); | + | header("Bez cyklu"); |
| - | // Bez cyklu | + | // Bez cyklu |
| - | boost::shared_ptr<RingNode> R3(new RingNode("RingNode3", boost::shared_ptr<RingNode>((RingNode*)NULL))); | + | boost::shared_ptr<RingNode> R3(new RingNode("RingNode3", |
| - | boost::shared_ptr<RingNode> R4(new RingNode("RingNode4", boost::shared_ptr<RingNode>(R3))); | + | boost::shared_ptr<RingNode>((RingNode*)NULL))); |
| - | cout << "R3 (" << R4->get_name() << ") with count " << R3.use_count() << endl; | + | boost::shared_ptr<RingNode> R4(new RingNode("RingNode4", |
| - | cout << "R4 (" << R4->get_name() << ") with count " << R4.use_count() << " connected to " << R4->get_node()->get_name() << endl; | + | boost::shared_ptr<RingNode>(R3))); |
| - | // Wszystkie węzły ulegną zniszczeniu jak powinny | + | 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() { | void shared_cycle() { | ||
| - | header("Cykl na shared_ptr"); | + | header("Cykl na shared_ptr"); |
| - | // Większy cykl, choć uzyskany tylko pośrednio, powoduje, że węzły nie | + | // 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 | + | // 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> R7(new RingNode("RingNode7", |
| - | boost::shared_ptr<RingNode> R8(new RingNode("RingNode8", boost::shared_ptr<RingNode>(R7))); | + | boost::shared_ptr<RingNode>((RingNode*)NULL))); |
| - | boost::shared_ptr<RingNode> R9(new RingNode("RingNode9", boost::shared_ptr<RingNode>(R8))); | + | boost::shared_ptr<RingNode> R8(new RingNode("RingNode8", |
| - | R7->connect(R9); | + | boost::shared_ptr<RingNode>(R7))); |
| - | cout << "R7 (" << R7->get_name() << ") with count " << R7.use_count() << " connected to " << R7->get_node()->get_name() << endl; | + | boost::shared_ptr<RingNode> R9(new RingNode("RingNode9", |
| - | cout << "R8 (" << R8->get_name() << ") with count " << R8.use_count() << " connected to " << R8->get_node()->get_name() << endl; | + | boost::shared_ptr<RingNode>(R8))); |
| - | cout << "R9 (" << R9->get_name() << ") with count " << R9.use_count() << " connected to " << R9->get_node()->get_name() << endl; | + | 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"<--------------------. | + | R7-->"R7"<--------node--------. |
| | | | | | | ||
| *--node-->"R8"<--R8 | | *--node-->"R8"<--R8 | | ||
| | | | | | | ||
| *--node-->"R9"<--R9 | *--node-->"R9"<--R9 | ||
| - | */ | + | */ |
| } | } | ||
| void weak_cycle() { | void weak_cycle() { | ||
| - | header("Cykl na weak_ptr"); | + | header("Cykl na weak_ptr"); |
| - | // "Słaby" cykl oparty o 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> R5(new WeakRingNode("WeakRingNode5", |
| - | boost::shared_ptr<WeakRingNode> R6(new WeakRingNode("WeakRingNode6", boost::shared_ptr<WeakRingNode>(R5))); | + | boost::shared_ptr<WeakRingNode>((WeakRingNode*)NULL))); |
| - | R5->connect(R6); | + | boost::shared_ptr<WeakRingNode> R6(new WeakRingNode("WeakRingNode6", |
| - | boost::weak_ptr<WeakRingNode> Wtmp1(R5); | + | boost::shared_ptr<WeakRingNode>(R5))); |
| - | boost::weak_ptr<WeakRingNode> Wtmp2(R6); | + | R5->connect(R6); |
| - | // Jak można zauważyć, weak_ptr nie zwiększa licznika odwołań do obiektu, | + | boost::weak_ptr<WeakRingNode> Wtmp1(R5); |
| - | // którego dotyczy, ani nie usuwa obiektu, gdy wielkość ta spadnie do zera. | + | boost::weak_ptr<WeakRingNode> Wtmp2(R6); |
| - | // Obiekt, do którego się odwołuje może zostać usunięty "bez jego wiedzy". | + | // Jak można zauważyć, weak_ptr nie zwiększa licznika odwołań do obiektu, |
| - | // Dlatego właśnie współpracuje z shared_ptr. | + | // którego dotyczy, ani nie usuwa obiektu, gdy wielkość ta spadnie do zera. |
| - | cout << "R5 (" << R5->get_name() << ") with count " << R5.use_count() << " connected to " << R5->get_node()->get_name() << endl; | + | // Obiekt, do którego się odwołuje może zostać usunięty "bez jego wiedzy". |
| - | cout << "R6 (" << R6->get_name() << ") with count " << R6.use_count() << " connected to " << R6->get_node()->get_name() << endl; | + | // Dlatego właśnie współpracuje z shared_ptr. |
| - | // Poprzez funkcję weak_ptr.lock(), która użyta jest w get_node(), weak_ptr | + | cout << "R5 (" << R5->get_name() << ") with count " << R5.use_count() << " |
| - | // gwarantuje nam, że zostanie wykonana dodatkowa kopia, a shared_ptr zajmie | + | connected to " << R5->get_node()->get_name() << endl; |
| - | // się zwiększeniem licznika odwołań, by obiekt nie zniknął podczas | + | cout << "R6 (" << R6->get_name() << ") with count " << R6.use_count() << " |
| - | // wykonywania na nim operacji. | + | connected to " << R6->get_node()->get_name() << endl; |
| - | // Jeśli obiekt zdążył zniknąć już wcześniej, podczas tworzenia shared_ptr z | + | // Poprzez funkcję weak_ptr.lock(), która użyta jest w get_node(), weak_ptr |
| - | // weak_ptr dostaniemy wyjątek bad_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() { | void shared_and_weak() { | ||
| - | header("Relacja miedzy shared_ptr i weak_ptr"); | + | header("Relacja miedzy shared_ptr i weak_ptr"); |
| - | cout << "Oryginalny shared_ptr:" << endl; | + | cout << "Oryginalny shared_ptr:" << endl; |
| - | boost::shared_ptr<Harry> shared1(new Harry); | + | boost::shared_ptr<Harry> shared1(new Harry); |
| - | cout << "shared1.count: " << shared1.use_count() << endl; | + | cout << "shared1.count: " << shared1.use_count() << endl; |
| - | cout << "weak_ptr z shared_ptr:" << endl; | + | cout << "weak_ptr z shared_ptr:" << endl; |
| - | boost::weak_ptr<Harry> weak1(shared1); | + | boost::weak_ptr<Harry> weak1(shared1); |
| - | cout << "shared1.count: " << shared1.use_count() << endl; | + | cout << "shared1.count: " << shared1.use_count() << endl; |
| - | cout << "weak1.count : " << weak1.use_count() << endl; | + | cout << "weak1.count : " << weak1.use_count() << endl; |
| - | cout << "shared_ptr z weak_ptr (z shared_ptr)" << endl; | + | cout << "shared_ptr z weak_ptr (z shared_ptr)" << endl; |
| - | boost::shared_ptr<Harry> shared2(weak1); | + | boost::shared_ptr<Harry> shared2(weak1); |
| - | cout << "shared1.count: " << shared1.use_count() << endl; | + | cout << "shared1.count: " << shared1.use_count() << endl; |
| - | cout << "weak1.count : " << weak1.use_count() << endl; | + | cout << "weak1.count : " << weak1.use_count() << endl; |
| - | cout << "shared2.count: " << shared2.use_count() << endl; | + | cout << "shared2.count: " << shared2.use_count() << endl; |
| } | } | ||
| void with_sharing_test(WithSharing& ws) { | void with_sharing_test(WithSharing& ws) { | ||
| - | header("Test enable_shared_from_this<>"); | + | header("Test enable_shared_from_this<>"); |
| - | boost::shared_ptr<WithSharing> ws_a(ws.get_shared()); | + | boost::shared_ptr<WithSharing> ws_a(ws.get_shared()); |
| - | cout << "Drugi udzial, use_count: " << ws_a.use_count() << endl; | + | cout << "Drugi udzial, use_count: " << ws_a.use_count() << endl; |
| - | /* . | + | /* . |
| - | * /|\ | + | * /|\ |
| - | * | | + | * | |
| - | * ------------------------------------------------- | + | * ------------------------------------------------- |
| - | * dwa niezależne fragmenty kodu, np. dwa wątki | + | * dwa niezależne fragmenty kodu, np. dwa wątki |
| - | * ------------------------------------------------- | + | * ------------------------------------------------- |
| - | * | | + | * | |
| - | * \|/ | + | * \|/ |
| - | * ' | + | * ' |
| - | */ | + | */ |
| - | boost::shared_ptr<WithSharing> ws_b(ws.get_shared()); | + | boost::shared_ptr<WithSharing> ws_b(ws.get_shared()); |
| - | cout << "Trzeci udzial, use_count: " << ws_b.use_count() << endl; | + | cout << "Trzeci udzial, use_count: " << ws_b.use_count() << endl; |
| } | } | ||
| void auto_ptr_demo() { | void auto_ptr_demo() { | ||
| - | header("auto_ptr - przy boost maly sens stosowania"); | + | header("auto_ptr - przy boost maly sens stosowania"); |
| - | /* | + | /* |
| - | * http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.0/classstd_1_1auto__ptr.html | + | * |
| - | * | + | 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 | + | * "auto_ptr does not meet the CopyConstructible and Assignable |
| - | * instantiating a Standard Library container with an auto_ptr results in | + | * requirements for Standard Library container elements and thus |
| - | * undefined behavior." | + | * 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 | + | * Reasumując - auto_ptr ciekawy nie jest. Potrafi tylko oddawać powiązanie z |
| - | * kontenerach nie jest możliwe. | + | * obiektem, natomiast nie potrafi się nim dzielić. Zastosowanie w |
| - | */ | + | * kontenerach nie jest możliwe. |
| + | */ | ||
| - | auto_ptr<Harry> a1(new Harry); | + | auto_ptr<Harry> a1(new Harry); |
| - | cout << "NEW. " << a1.get() << endl; | + | cout << "NEW. " << a1.get() << endl; |
| - | auto_ptr<Harry> a2(a1); | + | auto_ptr<Harry> a2(a1); |
| - | cout << "1st transfer, source: " << a1.get() << endl; | + | cout << "1st transfer, source: " << a1.get() << endl; |
| - | cout << "1st transfer, dest. : " << a2.get() << endl; | + | cout << "1st transfer, dest. : " << a2.get() << endl; |
| - | auto_ptr<Harry> a3 = a2; | + | auto_ptr<Harry> a3 = a2; |
| - | cout << "2nd transfer, source: " << a2.get() << endl; | + | cout << "2nd transfer, source: " << a2.get() << endl; |
| - | cout << "2nd transfer, dest. : " << a3.get() << endl; | + | cout << "2nd transfer, dest. : " << a3.get() << endl; |
| } | } | ||
| Linia 566: | Linia 609: | ||
| int main(int argc, char** argv) { | int main(int argc, char** argv) { | ||
| - | // ========================================================== | + | // ========================================================== |
| - | // Zestaw tego, czego robić nie wolno ze scoped_ptr | + | // Zestaw tego, czego robić nie wolno ze scoped_ptr |
| - | play_dirty_harry(); | + | play_dirty_harry(); |
| - | // shared_ptr | + | // shared_ptr |
| - | general_use(); | + | general_use(); |
| - | // Mniej interesujące | + | // Mniej interesujące |
| - | play_nice_harry(); | + | play_nice_harry(); |
| - | // Bardziej interesujące | + | // Bardziej interesujące |
| - | play_nice_harry3(); | + | play_nice_harry3(); |
| - | + | ||
| - | // scoped_array zamiast scoped_ptr - właściwe delete, konkretnie delete[] | + | // scoped_array zamiast scoped_ptr - właściwe delete, konkretnie delete[] |
| - | play_scoped_array(); | + | play_scoped_array(); |
| - | // Niewirtualny destruktor. Różnice między zwykłym wskaźnikiem a shared_ptr | + | // Niewirtualny destruktor. Różnice między zwykłym wskaźnikiem a shared_ptr |
| - | non_virt_diffs(); | + | non_virt_diffs(); |
| - | // ========================================================== | + | // ========================================================== |
| - | // Kontener STL | + | // Kontener STL |
| - | stl_container(); | + | stl_container(); |
| - | // ========================================================== | + | // ========================================================== |
| - | // Shared vs Weak a cykle | + | // Shared vs Weak a cykle |
| - | no_cycle(); | + | no_cycle(); |
| - | shared_cycle(); | + | shared_cycle(); |
| - | weak_cycle(); | + | weak_cycle(); |
| - | shared_and_weak(); | + | shared_and_weak(); |
| - | // ========================================================== | + | // ========================================================== |
| - | // GŁÓWNY POWÓD UŻYWANIA SMART_PTRów | + | // GŁÓWNY POWÓD UŻYWANIA SMART_PTRów |
| - | // komfort operatora "new" | + | // komfort operatora "new" |
| - | // z bezpieczeństwem zmiennych automatycznych | + | // z bezpieczeństwem zmiennych automatycznych |
| - | // ========================================================== | + | // ========================================================== |
| - | try { | + | try { |
| - | comfort_test(); | + | comfort_test(); |
| - | } catch (...) { | + | } catch (...) { |
| - | cout << "Caught!" << endl; | + | cout << "Caught!" << endl; |
| - | } | + | } |
| - | // ========================================================== | + | // ========================================================== |
| - | // Test enable_shared_from_this<> | + | // Test enable_shared_from_this<> |
| - | boost::shared_ptr<WithSharing> ws(new WithSharing); | + | boost::shared_ptr<WithSharing> ws(new WithSharing); |
| - | with_sharing_test(*ws); | + | with_sharing_test(*ws); |
| - | // ========================================================== | + | // ========================================================== |
| - | // std::auto_ptr | + | // std::auto_ptr |
| - | auto_ptr_demo(); | + | auto_ptr_demo(); |
| - | // ========================================================== | + | // ========================================================== |
| - | // Intrusive test | + | // Intrusive test |
| - | test_intrusive_ptr(); | + | test_intrusive_ptr(); |
| - | return 0; | + | return 0; |
| } | } | ||
| + | |||
| + | |||
| + | |||
| </code> | </code> | ||