Co to jest inteligentny wskaźnik i kiedy powinienem go użyć?


1818

Co to jest inteligentny wskaźnik i kiedy powinienem go użyć?



2
Zauważ, że implementacja std :: auto_ptr w Visual Studio 2005 jest strasznie zepsuta. Największa http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=98871 Największa http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101842 Użyj wzmocnij je zamiast tego.
Richard

25
Dwa doskonałe artykuły na ten temat: - Inteligentne wskaźniki - Co, dlaczego, które? - Guru tygodnia # 25
Lazer

1
Oto (bezpłatny) rozdział Alexandrescu na temat drobiazgowości tworzenia inteligentnych wskaźników różnych smaków: informit.com/articles/article.aspx?p=31529 W swojej implementacji używa argumentów szablonów jako „zasad”, aby określić, które atrybuty chce ( np. liczenie referencji), podczas gdy biblioteka standardowa używa osobnych klas. Zauważ, że pisał także zanim dostępne były referencje do wartości, aby umożliwić coś takiego jak std :: unique_ptr.
metal

Chciałbym dodać jeszcze jeden punkt do powyższego pytania, inteligentny wskaźnik std :: shared_ptr nie ma operatora indeksu dolnego i nie obsługuje arytmetyki ponter, możemy użyć get (), aby uzyskać wbudowany wskaźnik.
suresh m

Odpowiedzi:


1883

AKTUALIZACJA

Ta odpowiedź jest raczej stara i opisuje to, co było wtedy „dobre”, czyli inteligentne wskaźniki dostarczone przez bibliotekę Boost. Od wersji C ++ 11 standardowa biblioteka zapewnia wystarczającą liczbę typów inteligentnych wskaźników, dlatego powinieneś preferować użycie std::unique_ptr, std::shared_ptri std::weak_ptr.

Było też std::auto_ptr. Był bardzo podobny do wskaźnika celowniczego, tyle że miał także „specjalną” niebezpieczną zdolność do kopiowania - która również nieoczekiwanie przenosi własność.
Został przestarzały w C ++ 11 i usunięty w C ++ 17 , więc nie powinieneś go używać.

std::auto_ptr<MyObject> p1 (new MyObject());
std::auto_ptr<MyObject> p2 = p1; // Copy and transfer ownership. 
                                 // p1 gets set to empty!
p2->DoSomething(); // Works.
p1->DoSomething(); // Oh oh. Hopefully raises some NULL pointer exception.

STARA ODPOWIEDŹ

Inteligentny wskaźnik to klasa, która otacza „surowy” (lub „goły”) wskaźnik C ++, aby zarządzać żywotnością wskazywanego obiektu. Nie ma jednego inteligentnego typu wskaźnika, ale wszystkie próbują wyodrębnić surowy wskaźnik w praktyczny sposób.

Inteligentne wskaźniki powinny być preferowane nad surowymi wskaźnikami. Jeśli uważasz, że musisz użyć wskaźników (najpierw zastanów się, czy naprawdę tak robisz), zwykle powinieneś użyć inteligentnego wskaźnika, ponieważ może to złagodzić wiele problemów z surowymi wskaźnikami, głównie zapominając o usunięciu obiektu i wycieku pamięci.

Dzięki surowym wskaźnikom programista musi jawnie zniszczyć obiekt, gdy nie jest on już użyteczny.

// Need to create the object to achieve some goal
MyObject* ptr = new MyObject(); 
ptr->DoSomething(); // Use the object in some way
delete ptr; // Destroy the object. Done with it.
// Wait, what if DoSomething() raises an exception...?

Inteligentny wskaźnik przez porównanie definiuje zasadę, kiedy obiekt zostanie zniszczony. Nadal musisz stworzyć obiekt, ale nie musisz się już martwić o jego zniszczenie.

SomeSmartPtr<MyObject> ptr(new MyObject());
ptr->DoSomething(); // Use the object in some way.

// Destruction of the object happens, depending 
// on the policy the smart pointer class uses.

// Destruction would happen even if DoSomething() 
// raises an exception

Najprostsza w użyciu zasada obejmuje zakres obiektu opakowania inteligentnego wskaźnika, na przykład zaimplementowanego przez boost::scoped_ptrlub std::unique_ptr.

void f()
{
    {
       std::unique_ptr<MyObject> ptr(new MyObject());
       ptr->DoSomethingUseful();
    } // ptr goes out of scope -- 
      // the MyObject is automatically destroyed.

    // ptr->Oops(); // Compile error: "ptr" not defined
                    // since it is no longer in scope.
}

Pamiętaj, że std::unique_ptrnie można skopiować instancji. Zapobiega to wielokrotnemu usuwaniu wskaźnika (niepoprawnie). Możesz jednak przekazywać odniesienia do innych wywoływanych funkcji.

std::unique_ptrs są przydatne, gdy chcesz powiązać czas życia obiektu z określonym blokiem kodu lub jeśli osadziłeś go jako dane członka w innym obiekcie, czas życia tego innego obiektu. Obiekt istnieje do momentu opuszczenia zawierającego go bloku kodu lub do momentu zniszczenia zawierającego go obiektu.

Bardziej złożone zasady dotyczące inteligentnych wskaźników obejmują liczenie referencji przez wskaźnik. Pozwala to na skopiowanie wskaźnika. Gdy ostatnie „odniesienie” do obiektu zostanie zniszczone, obiekt zostanie usunięty. Ta polityka jest wdrażana przez boost::shared_ptri std::shared_ptr.

void f()
{
    typedef std::shared_ptr<MyObject> MyObjectPtr; // nice short alias
    MyObjectPtr p1; // Empty

    {
        MyObjectPtr p2(new MyObject());
        // There is now one "reference" to the created object
        p1 = p2; // Copy the pointer.
        // There are now two references to the object.
    } // p2 is destroyed, leaving one reference to the object.
} // p1 is destroyed, leaving a reference count of zero. 
  // The object is deleted.

Wskaźniki liczone w odniesieniach są bardzo przydatne, gdy czas życia obiektu jest znacznie bardziej skomplikowany i nie jest bezpośrednio powiązany z określoną sekcją kodu lub innym obiektem.

Istnieje jedna wada w stosunku do liczonych wskaźników - możliwość utworzenia wiszącego odniesienia:

// Create the smart pointer on the heap
MyObjectPtr* pp = new MyObjectPtr(new MyObject())
// Hmm, we forgot to destroy the smart pointer,
// because of that, the object is never destroyed!

Inną możliwością jest tworzenie referencji cyklicznych:

struct Owner {
   std::shared_ptr<Owner> other;
};

std::shared_ptr<Owner> p1 (new Owner());
std::shared_ptr<Owner> p2 (new Owner());
p1->other = p2; // p1 references p2
p2->other = p1; // p2 references p1

// Oops, the reference count of of p1 and p2 never goes to zero!
// The objects are never destroyed!

Aby obejść ten problem, zarówno Boost, jak i C ++ 11 zdefiniowały a, weak_ptraby zdefiniować słabe (niepoliczone) odwołanie do a shared_ptr.


7
Masz na myśli std::auto_ptr<MyObject> p1 (new MyObject());zamiast std::auto_ptr<MyObject> p1 (new Owner());?
Mateen Ulhaq,

35
Świetna odpowiedź. Byłoby miło, gdyby został zaktualizowany do wersji c ++ 11. Znalazłem tę odpowiedź, szukając informacji o nowym standardzie 11 i byłoby miło, gdyby przyszli użytkownicy mogli znaleźć zaktualizowane informacje. Wiem, że auto_ptr zostało wycofane. Wydaje mi się, że shated_ptr i poor_ptr istnieją zgodnie z opisem, i myślę, że scoped_ptr jest teraz standardem unikatowy_ptr. Jeśli to prawda, czy można zaktualizować tę odpowiedź?
SaulBack,

16
Stwierdzenie, że możliwość utworzenia wiszącego odniesienia jest wadą liczonych wskaźników, jest absolutnie szalone. Możliwe wiszące odniesienia są wadą dowolnego wskaźnika C ++ . W rzeczywistości właśnie tę wadę mają złagodzić inteligentne wskaźniki .
Michael Dorst

16
Jeśli zadeklarujesz wskaźnik na inteligentnym wskaźniku (tak jak w przykładzie), świadomie porzucisz wszystkie zalety inteligentnego wskaźnika. To nie jest wada ani wada projektowa, to najbardziej idiotyczne użycie, jakie można sobie wyobrazić.
Michael Dorst,

3
A const std::auto_ptrjest bezpieczny w użyciu, jeśli utkniesz w C ++ 03. Używałem go dość często do wzorca pimpl, dopóki nie uzyskałem dostępu do C ++ 11.
Toby Speight,

302

Oto prosta odpowiedź na współczesne C ++ (C ++ 11 i nowsze):

  • Co to jest inteligentny wskaźnik?
    Jest to typ, którego wartości mogą być używane jak wskaźniki, ale który zapewnia dodatkową funkcję automatycznego zarządzania pamięcią: Gdy inteligentny wskaźnik nie jest już używany, pamięć, na którą wskazuje, jest zwolniona (patrz także bardziej szczegółowa definicja na Wikipedii ).
  • Kiedy powinienem go użyć?
    W kodzie, który obejmuje śledzenie własności fragmentu pamięci, przydzielanie lub cofanie przydzielania; inteligentny wskaźnik często oszczędza ci potrzeby robienia tych rzeczy wprost.
  • Ale który inteligentny wskaźnik powinienem zastosować w którym z tych przypadków?
    • Użyj, std::unique_ptrgdy nie zamierzasz przechowywać wielu odwołań do tego samego obiektu. Na przykład użyj go jako wskaźnika do pamięci, który zostaje przydzielony po wejściu w pewien zakres i zwolniony po wyjściu z zakresu.
    • Użyj, std::shared_ptrgdy chcesz odwoływać się do swojego obiektu z wielu miejsc - i nie chcesz, aby Twój obiekt został cofnięty, dopóki wszystkie te odniesienia nie znikną.
    • Użyj, std::weak_ptrjeśli chcesz odwoływać się do swojego obiektu z wielu miejsc - w przypadku tych odniesień, dla których można zignorować i cofnąć przydział (aby zauważyć, że obiekt zniknął, gdy próbujesz wyrejestrować).
    • Nie używaj boost::inteligentnych wskaźników lub std::auto_ptrwyjątkowych przypadków, o których możesz przeczytać, jeśli musisz.
  • Hej, nie pytałem, którego użyć!
    Ach, ale naprawdę chciałeś, przyznaj się.
  • Kiedy więc powinienem używać zwykłych wskaźników?
    Głównie w kodzie, który nie zna własności pamięci. Zwykle byłoby to w funkcjach, które pobierają wskaźnik z innego miejsca i nie przydzielają ani nie przydzielają, i nie przechowują kopii wskaźnika, który przewyższa ich wykonanie.

5
Warto zauważyć, że chociaż inteligentne (będące właścicielami) wskaźniki pomagają w prawidłowym zarządzaniu pamięcią, surowe (nie będące właścicielami) wskaźniki są nadal przydatne do innych celów organizacyjnych w strukturach danych. Herb Sutter wygłosił świetną prezentację na ten temat na CppCon 2016, którą można zobaczyć na YouTube: Leak-Freedom in C ++ ... Domyślnie.
wiktor.wandachowicz

1
@ wiktor.wandachowicz T*jest do std::unique_ptr<T>tego, co std::weak_ptr<T>jeststd::shared_ptr<T>
Caleth

@Caleth: Nie, nie powiedziałbym tego.
einpoklum

1
@TonyTannous: Z poważaniem - To była poważna edycja; i nie czuję, że moja odpowiedź, która jest abstrakcyjna, potrzebuje jej. Sugeruję, aby uczynić przykład osobną odpowiedzią, podając link do niego w komentarzu.
einpoklum

112

Inteligentny wskaźnik jest podobny do wskaźnika z pewnymi dodatkowymi funkcjami, np. Automatycznym zwolnieniem pamięci, zliczaniem referencji itp.

Małe wprowadzenie jest dostępne na stronie Inteligentne wskaźniki - Co, dlaczego, co? .

Jednym z prostych typów inteligentnych wskaźników jest std::auto_ptr(rozdział 20.4.5 standardu C ++), który pozwala automatycznie zwolnić pamięć, gdy jest poza zakresem, i który jest bardziej niezawodny niż proste użycie wskaźnika, gdy są zgłaszane wyjątki, chociaż mniej elastyczne.

Innym wygodnym typem jest boost::shared_ptrimplementacja zliczania referencji i automatyczne zwalnianie pamięci, gdy nie ma żadnych referencji do obiektu. Pomaga to uniknąć wycieków pamięci i jest łatwy w użyciu do implementacji RAII .

Temat jest szczegółowo opisany w książce „C ++ Templates: The Complete Guide” autorstwa Davida Vandevoorde, Nicolai M. Josuttis , rozdział 20. Inteligentne wskaźniki. Niektóre tematy obejmowały:


2
Ostrzeżenie std::auto_ptrjest przestarzałe i bardzo odradza, ponieważ możesz przypadkowo przenieść własność. - C ++ 11 eliminuje potrzebę stosowania Boost,: std::unique_ptr, std::shared_ptristd::weak_ptr
ninMonkey

42

Definicje podane przez Chrisa, Sergdeva i Llyoda są poprawne. Wolę jednak prostszą definicję, aby moje życie było proste: inteligentny wskaźnik to po prostu klasa, która przeciąża operatory -> i *. Co oznacza, że ​​twój obiekt semantycznie wygląda jak wskaźnik, ale możesz sprawić, że zrobi to znacznie fajniejsze rzeczy, w tym zliczanie referencji, automatyczne niszczenie itp. shared_ptrI auto_ptrsą wystarczające w większości przypadków, ale mają własny zestaw małych osobliwości.


30

Inteligentny wskaźnik jest podobny do zwykłego (pisanego na maszynie) wskaźnika, takiego jak „char *”, z wyjątkiem sytuacji, gdy sam wskaźnik wykracza poza zasięg, wówczas to, na co wskazuje, jest również usuwane. Możesz go używać tak, jak zwykłego wskaźnika, używając „->”, ale nie, jeśli potrzebujesz rzeczywistego wskaźnika do danych. W tym celu możesz użyć „& * ptr”.

Przydaje się do:

  • Obiekty, które należy przypisać do nowego, ale które mają mieć taki sam okres istnienia jak coś na tym stosie. Jeśli obiekt jest przypisany do inteligentnego wskaźnika, zostaną one usunięte, gdy program opuści tę funkcję / blok.

  • Elementy danych klas, dzięki czemu po usunięciu obiektu usuwane są również wszystkie posiadane dane, bez specjalnego kodu w destruktorze (musisz upewnić się, że destruktor jest wirtualny, co prawie zawsze dobrze jest zrobić) .

Możesz nie chcieć używać inteligentnego wskaźnika, gdy:

  • ... wskaźnik nie powinien tak naprawdę posiadać danych ... tzn. gdy tylko używasz danych, ale chcesz, aby przetrwał funkcję, do której się odwołujesz.
  • ... inteligentny wskaźnik sam w sobie nie zostanie zniszczony. Nie chcesz, aby znajdował się w pamięci, która nigdy nie zostanie zniszczona (na przykład w obiekcie, który jest dynamicznie przydzielany, ale nie zostanie jawnie usunięty).
  • ... dwa inteligentne wskaźniki mogą wskazywać na te same dane. (Są jednak jeszcze mądrzejsze wskaźniki, które poradzą sobie z tym ... to nazywa się liczeniem referencji .)

Zobacz też:


18

Większość rodzajów inteligentnych wskaźników radzi sobie z usuwaniem wskaźnika do obiektu. Jest to bardzo przydatne, ponieważ nie musisz już myśleć o ręcznym usuwaniu obiektów.

Najczęściej używane inteligentne wskaźniki to std::tr1::shared_ptr(lub boost::shared_ptr), a rzadziej std::auto_ptr. Polecam regularne stosowanie shared_ptr.

shared_ptrjest bardzo wszechstronny i zajmuje się wieloma różnymi scenariuszami usuwania, w tym przypadkami, w których obiekty muszą być „przekazywane przez granice bibliotek DLL” (częsty przypadek koszmaru, jeśli różne libckody są używane między kodem a bibliotekami DLL).


18

Inteligentny wskaźnik to obiekt, który działa jak wskaźnik, ale dodatkowo zapewnia kontrolę nad budową, zniszczeniem, kopiowaniem, przenoszeniem i dereferencją.

Można wdrożyć własny inteligentny wskaźnik, ale wiele bibliotek zapewnia również inteligentne implementacje wskaźników, z których każda ma inne zalety i wady.

Na przykład Boost zapewnia następujące implementacje inteligentnych wskaźników:

  • shared_ptr<T>jest wskaźnikiem Tużycia licznika referencji w celu ustalenia, kiedy obiekt nie jest już potrzebny.
  • scoped_ptr<T>jest wskaźnikiem automatycznie usuwanym, gdy wykracza poza zakres. Zadanie nie jest możliwe.
  • intrusive_ptr<T>jest kolejnym wskaźnikiem liczącym odniesienia. Zapewnia lepszą wydajność niż shared_ptr, ale wymaga, aby ten typ Tmiał własny mechanizm zliczania referencji.
  • weak_ptr<T>jest słabym wskaźnikiem, działającym w połączeniu z shared_ptrunikaniem okrągłych odniesień.
  • shared_array<T>jest jak shared_ptr, ale dla tablic z T.
  • scoped_array<T>jest jak scoped_ptr, ale dla tablic z T.

Są to tylko jeden liniowy opis każdego z nich i mogą być używane według potrzeb, w celu uzyskania dalszych szczegółów i przykładów można zapoznać się z dokumentacją wzmocnienia.

Dodatkowo standardowa biblioteka C ++ zawiera trzy inteligentne wskaźniki; std::unique_ptrdla unikalnej własności, std::shared_ptrdla wspólnej własności i std::weak_ptr. std::auto_ptristniał w C ++ 03, ale teraz jest przestarzały.


Wyjaśnij, dlaczego scoped_ptrnie jest to deklaracja lokalna const unique_ptr- która również jest usuwana po wyjściu z zakresu.
einpoklum

11

Oto link do podobnych odpowiedzi: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Inteligentny wskaźnik to obiekt, który działa, wygląda i działa jak zwykły wskaźnik, ale oferuje większą funkcjonalność. W C ++ inteligentne wskaźniki są implementowane jako klasy szablonów, które zawierają w sobie wskaźnik i zastępują standardowe operatory wskaźnika. Mają wiele zalet w porównaniu ze zwykłymi wskaźnikami. Gwarantuje się, że zostaną zainicjowane jako wskaźniki zerowe lub wskaźniki do obiektu stosu. Sprawdzane jest przekierowanie przez wskaźnik zerowy. Nigdy nie jest konieczne usuwanie. Obiekty są automatycznie zwalniane, gdy ostatni wskaźnik do nich zniknie. Jednym ze znaczących problemów z tymi inteligentnymi wskaźnikami jest to, że w przeciwieństwie do zwykłych wskaźników, nie szanują dziedziczenia. Inteligentne wskaźniki nie są atrakcyjne dla kodu polimorficznego. Poniżej podano przykład implementacji inteligentnych wskaźników.

Przykład:

template <class X>
class smart_pointer
{
          public:
               smart_pointer();                          // makes a null pointer
               smart_pointer(const X& x)            // makes pointer to copy of x

               X& operator *( );
               const X& operator*( ) const;
               X* operator->() const;

               smart_pointer(const smart_pointer <X> &);
               const smart_pointer <X> & operator =(const smart_pointer<X>&);
               ~smart_pointer();
          private:
               //...
};

Ta klasa implementuje inteligentny wskaźnik do obiektu typu X. Sam obiekt znajduje się na stercie. Oto jak z niego korzystać:

smart_pointer <employee> p= employee("Harris",1333);

Podobnie jak inne przeciążone operatory, p będzie zachowywać się jak zwykły wskaźnik,

cout<<*p;
p->raise_salary(0.5);

9

http://en.wikipedia.org/wiki/Smart_pointer

W informatyce inteligentny wskaźnik to abstrakcyjny typ danych, który symuluje wskaźnik, zapewniając jednocześnie dodatkowe funkcje, takie jak automatyczne wyrzucanie elementów bezużytecznych lub sprawdzanie granic. Te dodatkowe funkcje mają na celu ograniczenie błędów spowodowanych niewłaściwym użyciem wskaźników przy jednoczesnym zachowaniu wydajności. Inteligentne wskaźniki zwykle śledzą obiekty, które na nie wskazują, w celu zarządzania pamięcią. Niewłaściwe użycie wskaźników jest głównym źródłem błędów: ciągłe przydzielanie, dezalokacja i odwoływanie się, które musi być wykonane przez program napisany przy użyciu wskaźników, bardzo prawdopodobne jest, że nastąpi przeciek pamięci. Inteligentne wskaźniki próbują zapobiec wyciekom pamięci, czyniąc dezalokację zasobów automatyczną: gdy wskaźnik do obiektu (lub ostatni z serii wskaźników) zostanie zniszczony,


6

Niech T będzie klasą w tym samouczku Wskaźniki w C ++ można podzielić na 3 typy:

1) Surowe wskaźniki :

T a;  
T * _ptr = &a; 

Przechowują adres pamięci do lokalizacji w pamięci. Używaj ostrożnie, ponieważ programy stają się trudne do śledzenia.

Wskaźniki ze stałymi danymi lub adresem {Czytaj wstecz}

T a ; 
const T * ptr1 = &a ; 
T const * ptr1 = &a ;

Wskaźnik do typu danych T, który jest stałą. Oznacza to, że nie można zmienić typu danych za pomocą wskaźnika. tj *ptr1 = 19; nie będzie działać. Ale możesz przesunąć wskaźnik. tj ptr1++ , ptr1--; etc zadziała. Czytaj wstecz: wskaźnik na typ T, który jest const

  T * const ptr2 ;

Stały wskaźnik do typu danych T. Oznacza to, że nie można przesunąć wskaźnika, ale można zmienić wartość wskazywaną przez wskaźnik. tzn. *ptr2 = 19będzie działać, ale ptr2++ ; ptr2--etc nie będzie działać. Czytaj wstecz: const wskaźnik do typu T.

const T * const ptr3 ; 

Wskaźnik stały do ​​stałego typu danych T. Oznacza to, że nie można przesunąć wskaźnika ani zmienić typu danych, aby był wskaźnikiem. tj. ptr3-- ; ptr3++ ; *ptr3 = 19;nie będzie działać

3) Inteligentne wskaźniki : { #include <memory>}

Współdzielony wskaźnik :

  T a ; 
     //shared_ptr<T> shptr(new T) ; not recommended but works 
     shared_ptr<T> shptr = make_shared<T>(); // faster + exception safe

     std::cout << shptr.use_count() ; // 1 //  gives the number of " 
things " pointing to it. 
     T * temp = shptr.get(); // gives a pointer to object

     // shared_pointer used like a regular pointer to call member functions
      shptr->memFn();
     (*shptr).memFn(); 

    //
     shptr.reset() ; // frees the object pointed to be the ptr 
     shptr = nullptr ; // frees the object 
     shptr = make_shared<T>() ; // frees the original object and points to new object

Zaimplementowano za pomocą zliczania referencji, aby śledzić, ile „rzeczy” wskazuje na obiekt wskazywany przez wskaźnik. Gdy liczba ta spadnie do 0, obiekt jest automatycznie usuwany, tzn. Obiekt jest usuwany, gdy wszystkie share_ptr wskazujące na obiekt wykraczają poza zakres. Pozbywa się to bólu głowy związanego z usuwaniem obiektów przydzielonych za pomocą nowego.

Słaby wskaźnik: Pomaga radzić sobie z cyklicznym odniesieniem, które powstaje podczas używania wskaźnika wspólnego Jeśli masz dwa obiekty wskazywane przez dwa wspólne wskaźniki, a wewnętrzny wskaźnik wspólny wskazuje na siebie wskaźnik wspólny, wówczas będzie to odwołanie cykliczne, a obiekt nie będzie zostać usunięte, gdy wskaźniki udostępnione wykroczą poza zakres. Aby rozwiązać ten problem, zmień element wewnętrzny z shared_ptr na poor_ptr. Uwaga: Aby uzyskać dostęp do elementu wskazywanego przez słaby wskaźnik, użyj funkcji lock (), zwraca ono parametr słabą_ptr.

T a ; 
shared_ptr<T> shr = make_shared<T>() ; 
weak_ptr<T> wk = shr ; // initialize a weak_ptr from a shared_ptr 
wk.lock()->memFn() ; // use lock to get a shared_ptr 
//   ^^^ Can lead to exception if the shared ptr has gone out of scope
if(!wk.expired()) wk.lock()->memFn() ;
// Check if shared ptr has gone out of scope before access

Zobacz: Kiedy przydatne jest std :: poor_ptr?

Unikalny wskaźnik: Lekki inteligentny wskaźnik z wyłączną własnością. Użyj, gdy wskaźnik wskazuje unikalne obiekty bez udostępniania obiektów między wskaźnikami.

unique_ptr<T> uptr(new T);
uptr->memFn(); 

//T * ptr = uptr.release(); // uptr becomes null and object is pointed to by ptr
uptr.reset() ; // deletes the object pointed to by uptr 

Aby zmienić obiekt wskazany przez unikatowy ptr, użyj semantyki przenoszenia

unique_ptr<T> uptr1(new T);
unique_ptr<T> uptr2(new T);
uptr2 = std::move(uptr1); 
// object pointed by uptr2 is deleted and 
// object pointed by uptr1 is pointed to by uptr2
// uptr1 becomes null 

Odniesienia: Zasadniczo mogą być traktowane jako wskaźniki const, tzn. Wskaźnik, który jest const i nie można go przenosić z lepszą składnią.

Zobacz: Jakie są różnice między zmienną wskaźnika i zmienną odniesienia w C ++?

r-value reference : reference to a temporary object   
l-value reference : reference to an object whose address can be obtained
const reference : reference to a data type which is const and cannot be modified 

Odniesienie: https://www.youtube.com/channel/UCEOGtxYTB6vo6MQ-WQ9W_nQ Dziękujemy Andre za wskazanie tego pytania.


3

Inteligentny wskaźnik to klasa, opakowanie normalnego wskaźnika. W przeciwieństwie do normalnych wskaźników, koło życia inteligentnego punktu opiera się na liczbie referencyjnej (ile razy przypisany jest obiekt inteligentnego wskaźnika). Tak więc za każdym razem, gdy inteligentny wskaźnik jest przypisywany do innego, wewnętrzny licznik referencyjny plus plus. I ilekroć obiekt wykracza poza zakres, licznik referencyjny minus minus.

Automatyczny wskaźnik, choć wygląda podobnie, całkowicie różni się od inteligentnego wskaźnika. Jest to wygodna klasa, która zwalnia zasób, gdy automatyczny obiekt wskaźnika wykracza poza zakres zmiennej. W pewnym stopniu sprawia, że ​​wskaźnik (do dynamicznie alokowanej pamięci) działa podobnie do zmiennej stosu (statycznie alokowanej w czasie kompilacji).


2

Inteligentne wskaźniki to te, w których nie musisz się martwić o alokację pamięci, udostępnianie zasobów i transfer.

Możesz bardzo dobrze używać tych wskaźników w podobny sposób, jak każda alokacja działa w Javie. W java Garbage Collector wykonuje lewę, podczas gdy w Smart Pointers trik odbywa się przez Destructors.


1

Istniejące odpowiedzi są dobre, ale nie obejmują tego, co zrobić, gdy inteligentny wskaźnik nie jest (kompletną) odpowiedzią na problem, który próbujesz rozwiązać.

Między innymi (dobrze wyjaśnione w innych odpowiedziach) użycie inteligentnego wskaźnika jest możliwym rozwiązaniem Jak wykorzystać klasę abstrakcyjną jako typ zwracanej funkcji? który został oznaczony jako duplikat tego pytania. Jednak pierwszym pytaniem, które kusi cię, by wskazać abstrakcyjną (a właściwie dowolną) klasę bazową jako typ zwracany w C ++, jest „co tak naprawdę masz na myśli?”. Dobra dokumentacja (z dalszymi odniesieniami) programowania obiektowego idiomatycznego w C ++ (i czym różni się on od innych języków) w dokumentacji biblioteki kontenerów wskaźników wskaźników. Podsumowując, w C ++ musisz pomyśleć o własności. Które inteligentne wskaźniki pomagają, ale nie są jedynym rozwiązaniem lub zawsze kompletnym rozwiązaniem (nie dają kopii polimorficznej) i nie zawsze są rozwiązaniem, które chcesz ujawnić w interfejsie (a powrót funkcji brzmi okropnie bardzo podobny interfejs). Na przykład może wystarczyć zwrócenie referencji. Ale we wszystkich tych przypadkach (inteligentny wskaźnik, kontener wskaźnika lub po prostu zwracanie odwołania) zmieniłeś zwrot z wartości na pewną formę odniesienia. Jeśli naprawdę potrzebujesz kopii, może być konieczne dodanie większej liczby „idiomów” lub przejście poza idiomatyczne (lub inne) OOP w C ++ do bardziej ogólnego polimorfizmu przy użyciu bibliotek takich jak Adobe Poly lub Boost. .

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.