logo

Punters intel·ligents en C++

Requisit previ: Apuntadors en C++

Els punters s'utilitzen per accedir als recursos que són externs al programa, com ara la memòria heap. Per tant, per accedir a la memòria de l'munt (si es crea alguna cosa dins de la memòria), s'utilitzen punters. Quan accedim a qualsevol recurs extern només fem servir una còpia del recurs. Si hi fem algun canvi, només el canviem a la versió copiada. Però, si fem servir un punter al recurs, podrem canviar el recurs original.



Problemes amb els punters normals

Alguns problemes amb els punters normals en C++ són els següents:

    Fuites de memòria: es produeix quan un programa assigna memòria repetidament però mai no s'allibera. Això comporta un consum excessiu de memòria i, finalment, provoca un error del sistema. Punters penjants: un punter penjant és un punter que es produeix en el moment en què l'objecte es desassigna de la memòria sense modificar el valor del punter. Punters salvatges: els punters salvatges són punters que es declaren i s'assignen memòria, però el punter mai s'inicia per apuntar a cap objecte o adreça vàlida. Incoherència de dades: la inconsistència de dades es produeix quan algunes dades s'emmagatzemen a la memòria però no s'actualitzen de manera coherent. Desbordament de memòria intermèdia: quan s'utilitza un punter per escriure dades en una adreça de memòria que es troba fora del bloc de memòria assignat. Això condueix a la corrupció de dades que poden ser explotades per atacants maliciosos.

Exemple:

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

>

>

Sortida

Memory limit exceeded>

Explicació: En funció diversió , crea un punter que apunta cap a Rectangle objecte. L'objecte Rectangle conté dos nombres enters, llargada, i amplada . Quan la funció diversió acaba, p es destruirà ja que és una variable local. Però, la memòria que va consumir no es desassignarà perquè ens hem oblidat d'utilitzar suprimir p; al final de la funció. Això vol dir que la memòria no serà lliure per ser utilitzada per altres recursos. Però, ja no necessitem la variable, necessitem la memòria.

En funció, principal , diversió s'anomena en un bucle infinit. Això vol dir que seguirà creant pàg . Assignarà més i més memòria, però no l'alliberarà perquè no l'hem desassignat. La memòria que s'ha perdut no es pot tornar a utilitzar. Que és una fuga de memòria. La totalitat Munt la memòria pot esdevenir inútil per aquest motiu.

Punters intel·ligents

Com hem sabut inconscientment, no desassignar un punter provoca una fuga de memòria que pot provocar una fallada del programa. Llenguatges Java, C# té Mecanismes de recollida d'escombraries per desassignar de manera intel·ligent la memòria no utilitzada per tornar-la a utilitzar. El programador no s'ha de preocupar per cap fuga de memòria. C++ presenta el seu propi mecanisme Punter intel·ligent . Quan l'objecte es destrueix, també allibera la memòria. Per tant, no cal que l'eliminem, ja que Smart Pointer ho gestionarà.

A Punter intel·ligent és una classe d'embolcall sobre un punter amb un operador com * i -> sobrecarregat. Els objectes de la classe de punter intel·ligent semblen punters normals. Però, a diferència Punters normals, pot desassignar i alliberar la memòria d'objectes destruïts.

La idea és fer una classe amb un punter, destructor, i operadors sobrecarregats com * i -> . Com que el destructor es crida automàticament quan un objecte surt de l'abast, la memòria assignada dinàmicament s'eliminaria automàticament (o el recompte de referència es pot disminuir).

Exemple:

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

>

>

Sortida

20>

Diferència entre punters i punters intel·ligents

Apuntador

Punter intel·ligent

Un punter és una variable que manté una adreça de memòria així com informació de tipus de dades sobre aquesta ubicació de memòria. Un punter és una variable que apunta a alguna cosa a la memòria. És un objecte assignat per una pila que embolcalla el punter. Els punters intel·ligents, en termes senzills, són classes que embolcallen un punter o punters amb àmbit.
No es destrueix de cap manera quan surt del seu abast Es destrueix a si mateix quan surt del seu abast
Els punters no són tan eficients ja que no admeten cap altra funció. Els punters intel·ligents són més eficients ja que tenen una característica addicional de gestió de memòria.
Estan molt centrats en la mà d'obra/manuals. Són de naturalesa automàtica/preprogramada.

Nota: Això només funciona per int . Aleshores, haurem de crear un punter intel·ligent per a cada objecte? No , hi ha una solució, Plantilla . En el codi següent com podeu veure T pot ser de qualsevol tipus.

conjunt vs mapa

Exemple:

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

>

>

Sortida

20>

Nota: Els punters intel·ligents també són útils en la gestió de recursos, com ara els identificadors de fitxers o els endolls de xarxa.

Tipus de punters intel·ligents

Les biblioteques C++ proporcionen implementacions de punters intel·ligents dels tipus següents:

  • auto_ptr
  • unique_ptr
  • shared_ptr
  • weak_ptr

auto_ptr

Amb auto_ptr, podeu gestionar objectes obtinguts a partir d'expressions noves i eliminar-los quan es destrueixi el propi auto_ptr. Quan es descriu un objecte mitjançant auto_ptr, emmagatzema un punter a un únic objecte assignat.

Nota: Aquesta plantilla de classe està obsoleta a partir de C++11. unique_ptr és una nova instal·lació amb una funcionalitat similar, però amb una seguretat millorada.

unique_ptr

unique_ptr emmagatzema només un punter. Podem assignar un objecte diferent eliminant l'objecte actual del punter.

Apuntadors únics en C++

Exemple:

C++




constructor de cordes

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

>

>

Sortida

50 50>

shared_ptr

Mitjançant l'ús de shared_ptr més d'un punter pot apuntar a aquest objecte alhora i mantindrà a Comptador de referència utilitzant el use_count() mètode.

Punter compartit en 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; }>

>

>

Sortida

50 50 50 2>

weak_ptr

Weak_ptr és un punter intel·ligent que conté una referència que no és propietari d'un objecte. És molt més semblant a shared_ptr excepte que no mantindrà a Comptador de referència . En aquest cas, un punter no tindrà una fortalesa a l'objecte. El motiu és que si suposem que els punters estan subjectant l'objecte i demanant altres objectes, llavors poden formar a Bloqueig.

Apuntador feble en 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; }>

>

>

Sortida

50 1>

Les biblioteques C++ proporcionen implementacions de punters intel·ligents en forma d'auto_ptr, unique_ptr, shared_ptr i weak_ptr