Warunek wstępny: Wskaźniki w C++
Wskaźniki służą do uzyskiwania dostępu do zasobów zewnętrznych w stosunku do programu – takich jak pamięć sterty. Tak więc, aby uzyskać dostęp do pamięci sterty (jeśli cokolwiek zostanie utworzone w pamięci sterty), używane są wskaźniki. Uzyskując dostęp do dowolnego zasobu zewnętrznego, po prostu używamy kopii zasobu. Jeśli dokonamy w nim jakichkolwiek zmian, po prostu zmienimy to w skopiowanej wersji. Jeśli jednak użyjemy wskaźnika do zasobu, będziemy mogli zmienić oryginalny zasób.
Problemy ze zwykłymi wskaźnikami
Niektóre problemy z normalnymi wskaźnikami w C++ są następujące:
- Wycieki pamięci: Dzieje się tak, gdy pamięć jest wielokrotnie przydzielana przez program, ale nigdy nie jest zwalniana. Prowadzi to do nadmiernego zużycia pamięci i ostatecznie prowadzi do awarii systemu. Wiszące wskaźniki: Wiszący wskaźnik to wskaźnik, który pojawia się w momencie, gdy obiekt zostaje zwolniony z pamięci bez modyfikowania wartości wskaźnika. Wskaźniki typu Wild: Wskaźniki typu Wild to wskaźniki zadeklarowane i przydzielone do pamięci, ale wskaźnik nigdy nie jest inicjowany w celu wskazania jakiegokolwiek prawidłowego obiektu lub adresu. Niespójność danych: Niespójność danych występuje, gdy niektóre dane są przechowywane w pamięci, ale nie są aktualizowane w spójny sposób. Przepełnienie bufora: Gdy wskaźnik jest używany do zapisywania danych pod adresem pamięci znajdującym się poza przydzielonym blokiem pamięci. Prowadzi to do uszkodzenia danych, które mogą zostać wykorzystane przez złośliwych atakujących.
Przykład:
C++
// C++ program to demonstrate working of a Pointers> #include> using> namespace> std;> class> Rectangle {> private>:> >int> length;> >int> breadth;> };> void> fun()> {> >// By taking a pointer p and> >// dynamically creating object> >// of class rectangle> >Rectangle* p =>new> Rectangle();> }> int> main()> {> >// Infinite Loop> >while> (1) {> >fun();> >}> }> |
>
>
Wyjście
Memory limit exceeded>
Wyjaśnienie: W działaniu zabawa , tworzy wskaźnik wskazujący na Prostokąt obiekt. Obiekt Prostokąt zawiera dwie liczby całkowite, długość, I szerokość . Kiedy funkcja zabawa kończy się, p zostanie zniszczone, ponieważ jest to zmienna lokalna. Jednak zużyta pamięć nie zostanie zwolniona, ponieważ zapomnieliśmy jej użyć usuń p; na końcu funkcji. Oznacza to, że pamięć nie będzie wolna do wykorzystania przez inne zasoby. Ale nie potrzebujemy już zmiennej, potrzebujemy pamięci.
W działaniu, główny , zabawa wywoływana jest w nieskończonej pętli. Oznacza to, że będzie nadal tworzyć P . Będzie przydzielać coraz więcej pamięci, ale jej nie zwolni, ponieważ jej nie zwolniliśmy. Zmarnowanej pamięci nie można wykorzystać ponownie. Co jest wyciekiem pamięci. Cały sterta z tego powodu pamięć może stać się bezużyteczna.
Inteligentne wskaźniki
Jak już wiemy, nieświadome zwolnienie wskaźnika powoduje wyciek pamięci, który może doprowadzić do awarii programu. Języki Java, C# ma Mechanizmy zbierania śmieci aby inteligentnie zwolnić nieużywaną pamięć i wykorzystać ją ponownie. Programista nie musi się martwić o jakiekolwiek wycieki pamięci. C++ ma swój własny mechanizm Inteligentny wskaźnik . Kiedy obiekt zostaje zniszczony, uwalnia się także pamięć. Nie musimy więc go usuwać, ponieważ poradzi sobie z tym Smart Pointer.
A Inteligentny wskaźnik jest klasą opakowania nad wskaźnikiem z operatorem like * I -> przeciążony. Obiekty klasy inteligentnych wskaźników wyglądają jak zwykłe wskaźniki. Ale w przeciwieństwie do Normalne wskaźniki, może zwolnić i zwolnić pamięć zniszczonego obiektu.
Pomysł jest taki, aby wziąć udział w zajęciach ze wskaźnikiem, niszczyciel, i przeciążone operatory, takie jak * I -> . Ponieważ destruktor jest wywoływany automatycznie, gdy obiekt wykracza poza zakres, dynamicznie przydzielana pamięć zostanie automatycznie usunięta (lub można zmniejszyć liczbę odwołań).
Przykład:
C++
// C++ program to demonstrate the working of Smart Pointer> #include> using> namespace> std;> class> SmartPtr {> >int>* ptr;>// Actual pointer> public>:> >// Constructor: Refer> >// techcodeview.com for use of> >// explicit keyword> >explicit> SmartPtr(>int>* p = NULL) { ptr = p; }> >// Destructor> >~SmartPtr() {>delete> (ptr); }> >// Overloading dereferencing operator> >int>& operator*() {>return> *ptr; }> };> int> main()> {> >SmartPtr ptr(>new> int>());> >*ptr = 20;> >cout << *ptr;> >// We don't need to call delete ptr: when the object> >// ptr goes out of scope, the destructor for it is> >// automatically called and destructor does delete ptr.> >return> 0;> }> |
>
>Wyjście
20>
Różnica między wskaźnikami a inteligentnymi wskaźnikami
| Wskaźnik | Inteligentny wskaźnik |
|---|---|
| Wskaźnik to zmienna przechowująca adres pamięci, a także informacje o typie danych o tej lokalizacji pamięci. Wskaźnik to zmienna wskazująca na coś w pamięci. | Jest to obiekt alokowany na stosie, zawijający wskaźniki. Inteligentne wskaźniki, mówiąc najprościej, to klasy zawijające wskaźnik lub wskaźniki o określonym zasięgu. |
| Nie ulega zniszczeniu w żadnej formie, gdy wychodzi poza swój zakres | Niszczy się sam, gdy wychodzi poza swój zasięg |
| Wskaźniki nie są tak wydajne, ponieważ nie obsługują żadnej innej funkcji. | Inteligentne wskaźniki są bardziej wydajne, ponieważ mają dodatkową funkcję zarządzania pamięcią. |
| Są bardzo pracochłonni/manualni. | Mają one charakter automatyczny/wstępnie zaprogramowany. |
Notatka: To działa tylko dla wew . Zatem będziemy musieli utworzyć inteligentny wskaźnik dla każdego obiektu? NIE , istnieje rozwiązanie, Szablon . W poniższym kodzie, jak widać T może być dowolnego typu.
instrukcja JavaScript if
Przykład:
C++
// C++ program to demonstrate the working of Template and> // overcome the issues which we are having with pointers> #include> using> namespace> std;> // A generic smart pointer class> template> <>class> T>>class> SmartPtr {> >T* ptr;>// Actual pointer> public>:> >// Constructor> >explicit> SmartPtr(T* p = NULL) { ptr = p; }> >// Destructor> >~SmartPtr() {>delete> (ptr); }> >// Overloading dereferencing operator> >T& operator*() {>return> *ptr; }> >// Overloading arrow operator so that> >// members of T can be accessed> >// like a pointer (useful if T represents> >// a class or struct or union type)> >T* operator->() {>return> ptr; }> };> int> main()> {> >SmartPtr<>int>>ptr(>new> int>());> >*ptr = 20;> >cout << *ptr;> >return> 0;> }> |
>
>Wyjście
20>
Notatka: Inteligentne wskaźniki przydają się także w zarządzaniu zasobami, takimi jak uchwyty plików czy gniazda sieciowe.
Rodzaje inteligentnych wskaźników
Biblioteki C++ zapewniają implementacje inteligentnych wskaźników następujących typów:
- auto_ptr
- unikalny_ptr
- wspólna_ptr
- słaby_ptr
auto_ptr
Używając auto_ptr, możesz zarządzać obiektami uzyskanymi z nowych wyrażeń i usuwać je, gdy sam auto_ptr zostanie zniszczony. Kiedy obiekt jest opisany poprzez auto_ptr, przechowuje wskaźnik do pojedynczego przydzielonego obiektu.
Notatka: Ten szablon klasy jest przestarzały od wersji C++ 11. Unique_ptr to nowy obiekt o podobnej funkcjonalności, ale z poprawionym bezpieczeństwem.
unikalny_ptr
unikalny_ptr przechowuje tylko jeden wskaźnik. Możemy przypisać inny obiekt usuwając bieżący obiekt ze wskaźnika.
Przykład:
C++
// C++ program to demonstrate the working of unique_ptr> // Here we are showing the unique_pointer is pointing to P1.> // But, then we remove P1 and assign P2 so the pointer now> // points to P2.> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> // --/ Smart Pointer> >unique_ptr P1(>new> Rectangle(10, 5));> >cout // This'll print 50 // unique_ptr P2(P1); unique_ptr P2; P2 = move(P1); // This'll print 50 cout // cout return 0; }> |
>
>
palindrom w JavieWyjście
50 50>
wspólna_ptr
Używając wspólna_ptr więcej niż jeden wskaźnik może wskazywać na ten jeden obiekt na raz i będzie on zachowywał a Licznik referencji używając liczba_użyć() metoda.

C++
// C++ program to demonstrate the working of shared_ptr> // Here both smart pointer P1 and P2 are pointing to the> // object Addition to which they both maintain a reference> // of the object> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> >//---/ Smart Pointer> >shared_ptr P1(>new> Rectangle(10, 5));> >// This'll print 50> >cout shared_ptr P2; P2 = P1; // This'll print 50 cout // This'll now not give an error, cout // This'll also print 50 now // This'll print 2 as Reference Counter is 2 cout << P1.use_count() << endl; return 0; }> |
>
>Wyjście
50 50 50 2>
słaby_ptr
Weak_ptr to inteligentny wskaźnik, który przechowuje odwołanie do obiektu niebędącego właścicielem. Jest znacznie bardziej podobny doshared_ptr, z tą różnicą, że nie obsługuje pliku a Licznik referencji . W tym przypadku wskaźnik nie będzie miał twierdzy na obiekcie. Powodem jest to, że jeśli założymy, że wskaźniki trzymają obiekt i proszą o inne obiekty, mogą utworzyć a Impas.

C++
// C++ program to demonstrate the working of weak_ptr> // Here both smart pointer P1 and P2 are pointing to the> // object Addition to which they both does not maintain> // a reference of the object> #include> using> namespace> std;> // Dynamic Memory management library> #include> class> Rectangle {> >int> length;> >int> breadth;> public>:> >Rectangle(>int> l,>int> b)> >{> >length = l;> >breadth = b;> >}> >int> area() {>return> length * breadth; }> };> int> main()> {> >//---/ Smart Pointer> >shared_ptr P1(>new> Rectangle(10, 5));> > >// create weak ptr> >weak_ptr P2 (P1);> > >// This'll print 50> >cout // This'll print 1 as Reference Counter is 1 cout << P1.use_count() << endl; return 0; }> |
>
>Wyjście
50 1>
Biblioteki C++ zapewniają implementacje inteligentnych wskaźników w postaci auto_ptr, Unique_ptr, wspólna_ptr i słabe_ptr