logo

Puntatori intelligenti in C++

Prerequisito: Puntatori in C++

I puntatori vengono utilizzati per accedere alle risorse esterne al programma, come la memoria heap. Quindi, per accedere alla memoria heap (se viene creato qualcosa all'interno della memoria heap), vengono utilizzati i puntatori. Quando accediamo a qualsiasi risorsa esterna utilizziamo semplicemente una copia della risorsa. Se apportiamo modifiche ad esso, lo modificheremo semplicemente nella versione copiata. Ma se utilizziamo un puntatore alla risorsa, saremo in grado di modificare la risorsa originale.



Problemi con i puntatori normali

Alcuni problemi con i puntatori normali in C++ sono i seguenti:

    Perdite di memoria: ciò si verifica quando la memoria viene allocata ripetutamente da un programma ma mai liberata. Ciò porta a un consumo eccessivo di memoria e alla fine porta a un arresto anomalo del sistema. Puntatori pendenti: un puntatore penzolante è un puntatore che si verifica nel momento in cui l'oggetto viene deallocato dalla memoria senza modificare il valore del puntatore. Puntatori selvaggi: i puntatori selvaggi sono puntatori che vengono dichiarati e allocati in memoria ma il puntatore non viene mai inizializzato per puntare a qualsiasi oggetto o indirizzo valido. Incoerenza dei dati: l'incoerenza dei dati si verifica quando alcuni dati vengono archiviati in memoria ma non vengono aggiornati in modo coerente. Buffer Overflow: quando un puntatore viene utilizzato per scrivere dati in un indirizzo di memoria esterno al blocco di memoria allocato. Ciò porta alla corruzione dei dati che possono essere sfruttati da aggressori malintenzionati.

Esempio:

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();> >}> }>

>

>

Produzione

Memory limit exceeded>

Spiegazione: In funzione divertimento , crea un puntatore che punta a Rettangolo oggetto. L'oggetto Rettangolo contiene due numeri interi, lunghezza, E ampiezza . Quando la funzione divertimento termina, p verrà distrutto poiché è una variabile locale. Ma la memoria consumata non verrà deallocata perché ci siamo dimenticati di usarla cancella p; al termine della funzione. Ciò significa che la memoria non sarà libera per essere utilizzata da altre risorse. Ma non abbiamo più bisogno della variabile, abbiamo bisogno della memoria.

In funzione, principale , divertimento viene chiamato in un ciclo infinito. Ciò significa che continuerà a creare P . Assegnerà sempre più memoria ma non la libererà poiché non l'abbiamo deallocata. La memoria sprecata non può essere riutilizzata. Che è una perdita di memoria. L'intero mucchio la memoria potrebbe diventare inutile per questo motivo.

Puntatori intelligenti

Come sappiamo inconsciamente, la mancata deallocazione di un puntatore provoca una perdita di memoria che può portare al crash del programma. Linguaggi Java, C# Meccanismi di raccolta dei rifiuti per deallocare in modo intelligente la memoria inutilizzata per essere riutilizzata. Il programmatore non deve preoccuparsi di eventuali perdite di memoria. C++ presenta il proprio meccanismo Puntatore intelligente . Quando l'oggetto viene distrutto libera anche la memoria. Pertanto, non è necessario eliminarlo poiché Smart Pointer lo gestirà.

UN Puntatore intelligente è una classe wrapper su un puntatore con un operatore simile * E -> sovraccarico. Gli oggetti della classe puntatore intelligente sembrano normali puntatori. Ma, a differenza Puntatori normali, può deallocare e liberare la memoria degli oggetti distrutti.

L'idea è di seguire una lezione con un puntatore, distruttore, e operatori sovraccarichi come * E -> . Poiché il distruttore viene chiamato automaticamente quando un oggetto esce dall'ambito, la memoria allocata dinamicamente verrebbe automaticamente eliminata (o il conteggio dei riferimenti potrebbe essere decrementato).

Esempio:

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;> }>

>

>

Produzione

20>

Differenza tra puntatori e puntatori intelligenti

Puntatore

Puntatore intelligente

Un puntatore è una variabile che mantiene un indirizzo di memoria e informazioni sul tipo di dati su quella posizione di memoria. Un puntatore è una variabile che punta a qualcosa in memoria. È un oggetto allocato nello stack con wrapper del puntatore. I puntatori intelligenti, in parole povere, sono classi che racchiudono un puntatore o puntatori con ambito.
Non viene distrutto in alcuna forma quando esce dal suo ambito Si distrugge quando esce dal suo ambito
I puntatori non sono così efficienti in quanto non supportano nessun'altra funzionalità. I puntatori intelligenti sono più efficienti in quanto dispongono di una funzionalità aggiuntiva di gestione della memoria.
Sono molto incentrati sul lavoro/manuali. Sono di natura automatica/preprogrammata.

Nota: Funziona solo per int . Quindi, dovremo creare Smart Pointer per ogni oggetto? NO , c'è una soluzione, Modello . Nel codice qui sotto come puoi vedere T può essere di qualsiasi tipo.

strumento di guarigione gimp

Esempio:

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;> }>

>

>

Produzione

numeri in alfabeto
20>

Nota: I puntatori intelligenti sono utili anche nella gestione delle risorse, come handle di file o socket di rete.

Tipi di puntatori intelligenti

Le librerie C++ forniscono implementazioni di puntatori intelligenti nei seguenti tipi:

  • auto_ptr
  • unique_ptr
  • condiviso_ptr
  • debole_ptr

auto_ptr

Utilizzando auto_ptr, puoi gestire gli oggetti ottenuti da nuove espressioni ed eliminarli quando auto_ptr stesso viene distrutto. Quando un oggetto viene descritto tramite auto_ptr, memorizza un puntatore a un singolo oggetto allocato.

Nota: Questo modello di classe è deprecato a partire da C++11. unique_ptr è una nuova struttura con funzionalità simili, ma con maggiore sicurezza.

unique_ptr

unique_ptr memorizza un solo puntatore. Possiamo assegnare un oggetto diverso rimuovendo l'oggetto corrente dal puntatore.

Puntatori univoci in C++

Esempio:

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; }>

>

>

Produzione

50 50>

condiviso_ptr

Usando condiviso_ptr più di un puntatore può puntare a questo oggetto alla volta e manterrà a Contatore di riferimento usando il use_count() metodo.

Puntatore condiviso in 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; }>

>

>

Produzione

50 50 50 2>

debole_ptr

Weak_ptr è un puntatore intelligente che contiene un riferimento non proprietario a un oggetto. È molto più simile a shared_ptr tranne che non manterrà un file Contatore di riferimento . In questo caso, un puntatore non avrà una roccaforte sull'oggetto. Il motivo è che se supponiamo che i puntatori contengano l'oggetto e richiedano altri oggetti, potrebbero formare a Una situazione di stallo.

Puntatore debole in 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; }>

>

>

Produzione

50 1>

Le librerie C++ forniscono implementazioni di puntatori intelligenti sotto forma di auto_ptr, unique_ptr, shared_ptr e debole_ptr