logo

Inteligentne wskaźniki w C++

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.

Unikalne wskaźniki w C++

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 Javie
Wyjś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.

Udostępniony wskaźnik w C++

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.

Słaby wskaźnik w C++

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