{"id":335,"date":"2018-09-25T17:09:46","date_gmt":"2018-09-25T15:09:46","guid":{"rendered":"http:\/\/www.kompikownia.pl\/?p=335"},"modified":"2018-11-22T20:58:43","modified_gmt":"2018-11-22T19:58:43","slug":"shared_ptr-inteligetne-wskazniki","status":"publish","type":"post","link":"https:\/\/www.kompikownia.pl\/index.php\/2018\/09\/25\/shared_ptr-inteligetne-wskazniki\/","title":{"rendered":"shared_ptr &#8211; Inteligentne wska\u017aniki"},"content":{"rendered":"<span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Czas czytania:<\/span> <span class=\"rt-time\">2<\/span> <span class=\"rt-label rt-postfix\">minut<\/span><\/span><p><a href=\"http:\/\/www.kompikownia.pl\/index.php\/2018\/09\/22\/inteligentne-wskazniki-unique_ptr\/\">W poprzednim artykule<\/a> zajmowali\u015bmy si\u0119 pierwszym z \u201einteligentnych\u201d wska\u017anik\u00f3w \u2013 wska\u017anikiem unikalnym (unique_ptr). Unique_ptr jest bardzo fajnym wska\u017anikiem, ale nie w ka\u017cdej sytuacji mo\u017cemy skorzysta\u0107 z jego dobrodziejstw. Czasami potrzebujemy \u201ewsp\u00f3\u0142dzieli\u0107\u201d obiekt i jego w\u0142asno\u015bci mi\u0119dzy dwoma lub wi\u0119cej miejscami w\u00a0programie. Za\u0142\u00f3\u017cmy, \u017ce tworzymy aplikacj\u0119 obs\u0142uguj\u0105c\u0105 przychodni\u0119. Mamy trzy rodzaje danych: pacjenci, lekarze, wizyty. Opisuj\u0105c wizyt\u0119, musimy wiedzie\u0107, kt\u00f3ry pacjent j\u0105 um\u00f3wi\u0142. Musimy zna\u0107 tak\u017ce lekarza, do kt\u00f3rego dany pacjent chce si\u0119 uda\u0107. To jest doskona\u0142e miejsce na u\u017cycie shared_ptr. U\u017cycie wska\u017anika wsp\u00f3\u0142dzielonego pozwoli nam np.: usun\u0105\u0107 pacjenta (gdy\u017c np.: przepisa\u0142 si\u0119 do innej przychodni) ale jednocze\u015bnie nie usunie to wizyt, kt\u00f3re dany pacjent ju\u017c odby\u0142, pozwalaj\u0105c na przeniesienie ich do archiwum.<\/p>\n<h1>Charakterystyka shared_ptr<\/h1>\n<p>Wewn\u0119trzna architektura shared_ptr jest nieco bardziej skomplikowana ni\u017c unique_ptr. Ka\u017cdy wska\u017anik shared_ptr posiada licznik referencji. Zlicza on, ile razy danym momencie wska\u017anik jest u\u017cywany w programie. Gdy tworzymy shared_ptr i\u00a0go inicjujemy, licznik referencji wskazuje warto\u015b\u0107 1. Podczas gdy skopiujemy go, np.: innej funkcji\/metody, warto\u015b\u0107 licznika referencji podskoczy w g\u00f3r\u0119. Je\u015bli dana metoda\/funkcja sko\u0144czy korzystanie ze wska\u017anika, zostaje on zniszczony. Warto\u015b\u0107 licznika referencji maleje. Gdy osi\u0105gnie warto\u015b\u0107 zero, pami\u0119\u0107 u\u017cywana przez wska\u017anik jest zwalniana. Zarazem obiekt, na kt\u00f3ry wskazuje wska\u017anik jest niszczony.<\/p>\n<p>Shared_ptr w swoim dzia\u0142aniu jest dosy\u0107 podobny do Garbage Collectora z Javy. Podobnie jak GB, shared_ptr zwalnia pami\u0119\u0107 gdy liczba referencji osi\u0105gnie zero. Mimo podobie\u0144stw, shared_ptr nie jest tym samym co Garbage Collector i\u00a0warto o\u00a0tym pami\u0119ta\u0107. Nie jest to tematem tego artyku\u0142u.<a href=\"https:\/\/stackoverflow.com\/questions\/4663385\/garbage-collection-vs-shared-pointers\"> Je\u015bli chcesz dowiedzie\u0107 si\u0119 wi\u0119cej, kliknij tu.<\/a><\/p>\n<p>Pozna\u0142e\u015b ju\u017c charakterystyk\u0119 shared_pointera. Zobaczmy wi\u0119c, jak w\u00a0praktyce si\u0119 nim pos\u0142ugiwa\u0107.<\/p>\n<h2>Tworzenie i zarz\u0105dzanie obiektem za pomoc\u0105 shared_ptr<\/h2>\n<p>Uwaga! Podobnie jak w przypadku unique_ptr, aby poni\u017csze programy si\u0119 skompilowa\u0142y, musisz w ustawieniach swojego IDE\/kompilatora w\u0142\u0105czy\u0107 flag\u0119 <strong>\u2011std=c++14<\/strong>.<\/p>\n<h3>Najprostszy przyk\u0142ad<\/h3>\n<pre lang=\"cpp\" line=\"1\">\r\n#include <iostream>\r\n#include <memory>\r\n\r\nusing namespace std;\r\nclass patient\r\n{\r\n    public:\r\n    patient() {\r\n        cout<<\"Patient constructor\"<<endl;\r\n    }\r\n    ~patient() {\r\n        cout<<\"Patient destructor\"<<endl;\r\n    }\r\n    string name;\r\n    string surname;\r\n};\r\nint main()\r\n{\r\n    shared_ptr<patient> fpat = make_shared<patient>();\r\n    fpat->name = \"Jan\";\r\n    fpat->surname = \"Kowalski\";\r\n    cout<<\"Read data from fpat shared_ptr\"<<endl;\r\n    cout<<fpat->name<<endl;\r\n    cout<<fpat->surname<<endl;\r\n    cout<<\"Reference counter: \"<<fpat.use_count()<<endl<<endl;\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Przeanalizujmy przyk\u0142ad zamieszczonego powy\u017cej kodu. Utworzyli\u015bmy sobie bardzo prost\u0105 klas\u0119 patient, kt\u00f3ra zawiera tylko dwa pola: name i surname typu string. Konstruktor i destruktor zosta\u0142y zamieszczone po to, aby\u015b wiedzia\u0142, w kt\u00f3rym momencie obiekt zosta\u0142 utworzony, a kiedy zosta\u0142 skasowany.<\/p>\n<p>Wydaje si\u0119, \u017ce funkcja main nie robi nic szczeg\u00f3lnego. Tworzymy wska\u017anik shared_ptr, kt\u00f3ry przechowuje obiekt typu patient. W przypadku unique_ptr u\u017cywali\u015bmy funkcji make_unique. Natomiast w przypadku shared_ptr u\u017cywamy analogicznej \u2013 <strong>make_shared<\/strong>. Nast\u0119pnie uzupe\u0142niamy pola klasy i\u00a0odczytujemy je za pomoc\u0105 utworzonego wcze\u015bniej wska\u017anika. W 25 linijce wykorzystujemy wbudowan\u0105 w shared_ptr metod\u0119 <strong>use_count()<\/strong>, kt\u00f3ra pozwala nam pozna\u0107 ile razy obiekt jest wsp\u00f3\u0142dzielony.<\/p>\n<h3>Shared_ptr jako argument funkcji<\/h3>\n<p>Sp\u00f3jrzmy teraz, jak zachowuje si\u0119 shared_ptr gdy przeka\u017cemy go jako argument funkcji. Podobnie jak w wypadku unique_ptr, u\u017cyjemy dw\u00f3ch sposob\u00f3w. Przeka\u017cemy shared_ptr najpierw za pomoc\u0105 kopii, a p\u00f3\u017aniej za pomoc\u0105 referencji.<\/p>\n<pre lang=\"cpp\" line=\"1\">\r\n#include <iostream>\r\n#include <memory>\r\n\r\nusing namespace std;\r\nclass patient\r\n{\r\n    public:\r\n    patient() {\r\n        cout<<\"Patient constructor\"<<endl;\r\n    }\r\n    ~patient() {\r\n        cout<<\"Patient destructor\"<<endl;\r\n    }\r\n    string name;\r\n    string surname;\r\n};\r\nvoid foo(shared_ptr<patient> pat) {\r\n    cout<<\"Foo function\"<<endl;\r\n    cout<<pat->name<<endl;\r\n    cout<<pat->surname<<endl;\r\n    cout<<\"Reference counter: \"<<pat.use_count()<<endl<<endl;\r\n}\r\nvoid foo_reference(shared_ptr<patient>& pat) {\r\n    cout<<\"foo_reference function\"<<endl;\r\n    cout<<pat->name<<endl;\r\n    cout<<pat->surname<<endl;\r\n    cout<<\"Reference counter: \"<<pat.use_count()<<endl<<endl;\r\n}\r\nint main()\r\n{\r\n    shared_ptr<patient> fpat = make_shared<patient>();\r\n    fpat->name = \"Jan\";\r\n    fpat->surname = \"Kowalski\";\r\n    cout<<\"Read data from fpat shared_ptr\"<<endl;\r\n    cout<<fpat->name<<endl;\r\n    cout<<fpat->surname<<endl;\r\n    cout<<\"Reference counter: \"<<fpat.use_count()<<endl<<endl;\r\n\r\n    foo(fpat);\r\n    cout<<\"After foo main function\"<<endl;\r\n    cout<<fpat->name<<endl;\r\n    cout<<fpat->surname<<endl;\r\n    cout<<\"Reference counter: \"<<fpat.use_count()<<endl<<endl;\r\n    foo_reference(fpat);\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Bazujemy na kodzie z pierwszego przyk\u0142adu. Jak pewnie zauwa\u017cy\u0142e\u015b, zosta\u0142y dodane dwie funkcje: foo i foo_reference. Obydwie nie robi\u0105 nic szczeg\u00f3lnego \u2013 ot \u2013 wypisuj\u0105 zawarto\u015b\u0107 p\u00f3l name i surname. Ka\u017cda z nich wy\u015bwietla tak\u017ce warto\u015b\u0107 licznika referencji za pomoc\u0105 metody use_count. Sp\u00f3jrz na wynik dzia\u0142ania powy\u017cszego programu:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-336\" src=\"http:\/\/www.kompikownia.pl\/wp-content\/uploads\/2018\/09\/shared_ptr_sc1.png\" alt=\"przyk\u0142ad 1 shared_ptr\" width=\"403\" height=\"331\" \/><\/p>\n<p>Metoda main wy\u015bwietla to samo co w poprzednim przyk\u0142adzie. Nie sta\u0142o si\u0119 tutaj nic szczeg\u00f3lnego. Ciekawy jest natomiast wynik dzia\u0142ania funkcji foo. Je\u015bli spojrzysz na deklaracj\u0119, zauwa\u017cysz, \u017ce przekazywali\u015bmy tam shared_ptr przez kopi\u0119. I rezultat takiego post\u0119powania doskonale wida\u0107 w wynikach dzia\u0142ania funkcji. Wska\u017anik shared_ptr zosta\u0142 \u201eskopiowany\u201d, ale sam obiekt nie. Co na to wskazuje? Wzrost o 1 liczby istniej\u0105cych referencji. W chwili dzia\u0142ania funkcji foo istniej\u0105 dwie kopie wska\u017anika shared_ptr wskazuj\u0105cego na obiekt \u201eJan Kowalski\u201d. Jedna kopia znajduje si\u0119 w funkcji main, a druga w funkcji foo.<\/p>\n<p>W momencie kiedy funkcja foo zako\u0144czy swoje dzia\u0142anie, wska\u017anik wskazuj\u0105cy na obiekt zostanie zniszczony. Sam obiekt nie zosta\u0142 unicestwiony, gdy\u017c warto\u015b\u0107 licznika referencji jest dalej wi\u0119ksza od zera (istnieje jeszcze jeden wska\u017anik na obiekt w funkcji main).<\/p>\n<p>Gdy przekazujemy shared_ptr przez referencj\u0119, warto\u015b\u0107 licznika referencji nie jest zwi\u0119kszana. Dzieje si\u0119 tak, gdy\u017c, przekazuj\u0105c obiekt przez referencj\u0119, przekazujemy niejako ten sam wska\u017anik, kt\u00f3ry istnieje w funkcji main. Nie jest wykonywana jego kopia, a co za tym idzie, warto\u015b\u0107 licznika referencji r\u00f3wnie\u017c nie jest zwi\u0119kszana.<\/p>\n<p>Destruktor obiektu pacjenta jest wywo\u0142ywany wraz z zako\u0144czeniem pracy funkcji main, a wi\u0119c wtedy, gdy wszystkie istniej\u0105ce wska\u017aniki shared_ptr wskazuj\u0105ce na nasz obiekt zostan\u0105 zniszczone.<\/p>\n<h1>Shared_ptr z kontenerami<\/h1>\n<p>Zar\u00f3wno shared_ptr jak i unique_ptr mo\u017cna u\u017cywa\u0107 w po\u0142\u0105czeniu z kontenerami (np.: vector). Sp\u00f3jrz na poni\u017cszy przyk\u0142ad:<\/p>\n<pre lang=\"cpp\" line=\"1\">\r\n#include <iostream>\r\n#include <memory>\r\n#include <vector>\r\nusing namespace std;\r\nclass patient\r\n{\r\n    public:\r\n    patient(string name,string surname) {\r\n        this->name = name;\r\n        this->surname = surname;\r\n        cout<<\"Patient \"<<this->name<<\" \"<<this->surname<<\" constructor\"<<endl;\r\n    }\r\n    ~patient() {\r\n        cout<<\"Patient \"<<this->name<<\" \"<<this->surname<<\" destructor\"<<endl;\r\n    }\r\n    void printNameSurname() {cout<<name<< \" \"<<surname;}\r\n    string name;\r\n    string surname;\r\n};\r\nvoid printPatientData(shared_ptr<patient> patient) {\r\n    cout<<\"printPatientData function\"<<endl;\r\n    patient->printNameSurname();\r\n    cout<<endl<<\"Reference counter: \"<<patient.use_count()<<endl<<endl;\r\n}\r\nvoid modifyPatientData(shared_ptr<patient> patient,string name,string surname) {\r\n    cout<<\"modifyPatientData function\"<<endl;\r\n    patient->name = name;\r\n    patient->surname = surname;\r\n    patient->printNameSurname();\r\n    cout<<endl<<\"Reference counter: \"<<patient.use_count()<<endl<<endl;\r\n}\r\nint main()\r\n{\r\n    vector<shared_ptr<patient>> vector_of_patients;\r\n    vector_of_patients.push_back(make_shared<patient>(\"Adam\",\"Nowak\"));\r\n    vector_of_patients.push_back(make_shared<patient>(\"Jan\",\"Kowalski\"));\r\n    vector_of_patients.push_back(make_shared<patient>(\"Amadeusz\",\"Mozart\"));\r\n    shared_ptr<patient> add_patient = vector_of_patients[2];\r\n    printPatientData(vector_of_patients[0]);\r\n    modifyPatientData(vector_of_patients[0],\"Juliusz\",\"Cezar\");\r\n    cout<<\"Return to main\"<<endl;\r\n    vector_of_patients[0]->printNameSurname();\r\n    cout<<endl<<\"Reference counter: \"<<vector_of_patients[0].use_count()<<endl;\r\n    cout<<\"Vector clear\"<<endl;\r\n    vector_of_patients.clear();\r\n    cout<<\"After vector clear\"<<endl;\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Wynik dzia\u0142ania powy\u017cszego programu przedstawia screen:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-337\" src=\"http:\/\/www.kompikownia.pl\/wp-content\/uploads\/2018\/09\/shared_ptr_sc2.png\" alt=\"przyk\u0142ad 2 shared_ptr \" width=\"374\" height=\"326\" \/><\/p>\n<p>Tworzymy sobie vector, do kt\u00f3rego dodajemy trzech pacjent\u00f3w. W 38 linijce tworzymy kopi\u0119 shared_ptr\u2019a za pomoc\u0105 operatora przypisania. W\u00a0tej chwili licznik referencji zmiennych add_patient i vector_of_patients[2] wynosi 2. Linijka 40 i funkcja modifyPatientData pokazuje, \u017ce wska\u017anik dzia\u0142a tak jak powinien \u2013 zmieniamy obiekt i odczyt tego obiektu za pomoc\u0105 dowolnego shared_ptra ujawni nam nowe uaktualnione w\u0142a\u015bciwo\u015bci.<\/p>\n<p>W linijce 45 czy\u015bcimy vector.\u00a0 Destruktory Juliusza Cezara i Jana Kowalskiego zosta\u0142y uruchomione. A dlaczego nie Amadeusza Mozarta? Bo jak pami\u0119tasz, istnieje jeszcze jeden wska\u017anik na ten obiekt, kt\u00f3ry tworzyli\u015bmy w linijce 38. Wyj\u015bcie z funkcji main spowoduje zniszczenie wska\u017anika add_patient. Licznik referencji spadnie wtedy do zera. Obiekt Amadeusza Mozarta b\u0119dzie skasowany.<\/p>\n<h2>Przenoszenie w\u0142asno\u015bci wska\u017anika wsp\u00f3\u0142dzielonego<\/h2>\n<p>Gdy poznawali\u015bmy unique_ptra, nauczyli\u015bmy si\u0119 obs\u0142ugi funkcji move. Jak pewnie pami\u0119tasz, przenosi ona \u201ew\u0142asno\u015b\u0107\u201d obiektu z jednego wska\u017anika na drugi. Move wsp\u00f3\u0142pracuje tak\u017ce ze wska\u017anikami wsp\u00f3\u0142dzielonymi. Sp\u00f3jrz na poni\u017cszy przyk\u0142ad:<\/p>\n<pre lang=\"cpp\" line=\"1\">\r\n#include <iostream>\r\n#include <memory>\r\n#include <assert.h>\r\nusing namespace std;\r\n\r\nint main()\r\n{\r\n    shared_ptr<int> wsk1 = make_shared<int>(20);\r\n    assert(wsk1);\r\n    cout<<\"wsk1 value: \"<<*wsk1<<endl;\r\n    cout<<\"wsk1 reference number: \"<<wsk1.use_count();\r\n    shared_ptr<int> wsk2 = move(wsk1);\r\n    assert(wsk2);\r\n    cout<<endl<<endl<<\"After move wsk1 to wsk2\"<<endl;\r\n    cout<<\"wsk2 value: \"<<*wsk2<<endl;\r\n    cout<<\"wsk2 reference number: \"<<wsk2.use_count()<<endl;\r\n    assert(wsk1);\r\n    cout<<\"wsk1 value: \"<<*wsk1<<endl;\r\n    cout<<\"wsk1 reference number: \"<<wsk1.use_count();\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Tworzymy wska\u017anik shared_ptr wsk1, kt\u00f3ry wskazuje na liczb\u0119 typu int. Wy\u015bwietlamy sobie te informacje w kolejnych linijkach. Nast\u0119pnie przenosimy \u201ew\u0142asno\u015b\u0107\u201d tej zmiennej do drugiego wska\u017anika wsk2. Wy\u015bwietlenie danych z wsk2 uda nam si\u0119 ale asercja umieszczona w linijce 17 udowodni, \u017ce wsk1 w tej chwili jest r\u00f3wny null.<\/p>\n<h2>C++17 i alokowanie tablic za pomoc\u0105 shared_ptr<\/h2>\n<h3>C++14<\/h3>\n<p>Czasami mo\u017ce zaistnie\u0107 potrzeba utworzenia wska\u017anika na tablic\u0119. W standardzie C++14 rzucono nam pod nogi troch\u0119 k\u0142\u00f3d. Sp\u00f3jrz na poni\u017cszy kod.<\/p>\n<pre lang=\"cpp\" line=\"1\">\r\n#include <iostream>\r\n#include <memory>\r\nusing namespace std;\r\n\r\nint main()\r\n{\r\n    shared_ptr<int> int_table(new int[10],default_delete<int[]>());\r\n    for(size_t i = 0;i<10;i++) {\r\n        int_table.get()[i] = i;\r\n    }\r\n    for(size_t i = 0;i<10;i++) {\r\n        cout<<\"int_table[\"<<i<<\"] = \"<<int_table.get()[i]<<endl;\r\n    }\r\n    return 0;\r\n}\r\n<\/pre>\n<p>Linijka nr 7. Tworzymy wska\u017anik dosy\u0107 niestandardowo. U\u017cywamy staromodnego new. Dodatkowo pojawia si\u0119 dziwne \u201edefault_delete\u201d. O co chodzi?<\/p>\n<p>Shared_ptry nie posiadaj\u0105 domy\u015blnie wsparcia dla tablic. Aby utworzy\u0107 taki wska\u017anik, opr\u00f3cz jawnego u\u017cycia operatora new musimy zadeklarowa\u0107 w\u0142asn\u0105 \u201epolityk\u0119 usuwania\u201d. Je\u015bli nie u\u017cyliby\u015bmy default_delete&lt;int[]&gt;, to shared_ptr przy usuwaniu obiektu u\u017cy\u0142by delete zamiast delete[]. Spowodowa\u0142oby to, jak pewnie si\u0119 domy\u015blasz wyciek pami\u0119ci. A tego staramy si\u0119 za wszelk\u0105 cen\u0119 unikn\u0105\u0107.<\/p>\n<p>Dost\u0119p do element\u00f3w takiej tablicy tak\u017ce nie jest zbyt intuicyjny. Musimy jawnie u\u017cywa\u0107 metody get.<\/p>\n<h3>C++17<\/h3>\n<p>Standard C++17 dodaje obs\u0142ug\u0119 tablic do wska\u017anik\u00f3w wsp\u00f3\u0142dzielonych. Program realizuj\u0105cy takie same zadanie jak wy\u017cej wygl\u0105da\u0142by wtedy nast\u0119puj\u0105co:<\/p>\n<pre lang=\"cpp\" line=\"1\">\r\n#include <memory>\r\n#include <iostream>\r\n#include <cstdlib>\r\nusing namespace std;\r\n\r\nint main()\r\n{\r\n\tshared_ptr<int[]> int_table(new int[10]); \r\n\tfor (size_t i = 0; i < 10; i++) {\r\n\t\tint_table[i] = i;\r\n\t}\r\n\tfor (size_t i = 0; i < 10; i++) {\r\n\t\tcout << \"int_table[\" << i << \"] = \" << int_table[i] << endl;\r\n\t}\r\n\tsystem(\"pause\");\r\n    return 0;\r\n}\r\n<\/pre>\n<p>(Program powy\u017cej kompiluje si\u0119 pod Visual Studio 2017. Nie kompiluje si\u0119 pod GCC z C::B 17.12 mimo w\u0142\u0105czenia obs\u0142ugi C++17)<\/p>\n<p>Prawda, \u017ce jest o wiele pro\u015bciej? Normalnie tworzymy tablic\u0119 (musimy u\u017cy\u0107 operatora new, ale nie jest to nic z\u0142ego) i normalnie si\u0119 do niej odwo\u0142ujemy, za pomoc\u0105 nawias\u00f3w kwadratowych. Wska\u017anik wsp\u00f3\u0142dzielony zarz\u0105dza t\u0105 tablic\u0105 jak ka\u017cdym innym obiektem i nie powoduje wyciek\u00f3w pami\u0119ci.<\/p>\n<h1>Shared_ptr \u2013 rozwi\u0105zanie wszelkich problem\u00f3w?<\/h1>\n<p>Shared_ptr jest wspania\u0142ym wska\u017anikiem \u201einteligentnym\u201d kt\u00f3ry pozwala rozwi\u0105za\u0107 wiele problem\u00f3w. Pami\u0119taj tylko, aby go nie \u201enadu\u017cywa\u0107\u201d. Shared_ptr jest nieco wolniejszy od unique_ptr i zajmuje nieco wi\u0119cej miejsca. W projektach ma\u0142ej skali nie gra to roli, ale gdyby twoja aplikacja si\u0119 rozros\u0142a, ta pozornie drobna r\u00f3\u017cnica w wydajno\u015bci mo\u017ce spowodowa\u0107 problemy.<\/p>\n<p>Nie pokaza\u0142em praktycznego przyk\u0142adu u\u017cycia shared_ptr. Zobaczysz taki w\u00a0nast\u0119pnym artykule z serii, w kt\u00f3rym om\u00f3wi\u0119 wska\u017anik weak_ptr.<\/p>\n<p>Kod wszystkich przyk\u0142ad\u00f3w umieszczonych w tym artykule <a href=\"https:\/\/github.com\/karol221-10\/blog_apps\/tree\/master\/shared_ptr\">znajduje si\u0119 w tym miejscu na platformie GitHub.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">Czas czytania:<\/span> <span class=\"rt-time\">2<\/span> <span class=\"rt-label rt-postfix\">minut<\/span><\/span> W poprzednim artykule zajmowali\u015bmy si\u0119 pierwszym z \u201einteligentnych\u201d wska\u017anik\u00f3w \u2013 wska\u017anikiem unikalnym (unique_ptr). Unique_ptr jest bardzo fajnym wska\u017anikiem, ale nie w ka\u017cdej sytuacji mo\u017cemy skorzysta\u0107 z jego dobrodziejstw. Czasami potrzebujemy &#8230;<\/p>\n","protected":false},"author":1,"featured_media":463,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[31],"tags":[],"_links":{"self":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/335"}],"collection":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/comments?post=335"}],"version-history":[{"count":16,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/335\/revisions"}],"predecessor-version":[{"id":357,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/posts\/335\/revisions\/357"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/media\/463"}],"wp:attachment":[{"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/media?parent=335"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/categories?post=335"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.kompikownia.pl\/index.php\/wp-json\/wp\/v2\/tags?post=335"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}