Inteligentné ukazovatele v C++
Predpoklad: Ukazovatele v C++
Ukazovatele sa používajú na prístup k zdrojom, ktoré sú pre program externé – ako je halda pamäte. Takže na prístup k pamäti haldy (ak sa niečo vytvorí v pamäti haldy) sa používajú ukazovatele. Pri prístupe k akémukoľvek externému zdroju používame iba kópiu zdroja. Ak v ňom urobíme nejaké zmeny, zmeníme ho iba v skopírovanej verzii. Ak však použijeme ukazovateľ na zdroj, budeme môcť zmeniť pôvodný zdroj.
Problémy s normálnymi ukazovateľmi
Niektoré problémy s normálnymi ukazovateľmi v C++ sú nasledovné:
- Úniky pamäte: K tomu dochádza, keď je pamäť opakovane prideľovaná programom, ale nikdy sa neuvoľňuje. To vedie k nadmernej spotrebe pamäte a nakoniec vedie k zlyhaniu systému. Visiace ukazovatele: Visiaci ukazovateľ je ukazovateľ, ktorý sa vyskytuje v čase, keď je objekt zrušený z pamäte bez zmeny hodnoty ukazovateľa. Divoké ukazovatele: Divoké ukazovatele sú ukazovatele, ktoré sú deklarované a pridelená pamäť, ale ukazovateľ nie je nikdy inicializovaný, aby ukazoval na akýkoľvek platný objekt alebo adresu. Nekonzistencia údajov: Nekonzistencia údajov nastáva, keď sú niektoré údaje uložené v pamäti, ale nie sú aktualizované konzistentným spôsobom. Pretečenie vyrovnávacej pamäte: Keď sa ukazovateľ používa na zapisovanie údajov na adresu pamäte, ktorá je mimo prideleného pamäťového bloku. To vedie k poškodeniu údajov, ktoré môžu zneužiť zákerní útočníci.
Príklad:
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();> > }> }> |
Výkon
Memory limit exceeded
Vysvetlenie: Vo funkcii zábava , vytvorí ukazovateľ, ktorý ukazuje na Obdĺžnik objekt. Objekt Obdĺžnik obsahuje dve celé čísla, dĺžka, a šírka . Keď funkcia zábava skončí, p sa zničí, keďže ide o lokálnu premennú. Pamäť, ktorú spotrebovala, však nebude uvoľnená, pretože sme ju zabudli použiť vymazať p; na konci funkcie. To znamená, že pamäť nebude môcť byť voľne použitá inými zdrojmi. Ale už nepotrebujeme premennú, potrebujeme pamäť.
Vo funkcii, Hlavná , zábava sa volá v nekonečnej slučke. To znamená, že bude pokračovať vo vytváraní p . Pridelí stále viac pamäte, ale neuvoľní ich, keďže sme ju nepridelili. Premrhaná pamäť sa nedá znova použiť. Čo je únik pamäte. Celá hromada pamäť môže byť z tohto dôvodu zbytočná.
Inteligentné ukazovatele
Ako vieme, nevedomé uvoľnenie ukazovateľa spôsobuje únik pamäte, ktorý môže viesť k zlyhaniu programu. Jazyky Java, C# má Mechanizmy zberu odpadu na inteligentné uvoľnenie nevyužitej pamäte na opätovné použitie. Programátor sa nemusí obávať žiadneho úniku pamäte. C++ prichádza s vlastným mechanizmom, ktorý je Inteligentný ukazovateľ . Keď je objekt zničený, uvoľní sa aj pamäť. Nemusíme ho teda odstraňovať, pretože to zvládne Smart Pointer.
A Inteligentný ukazovateľ je trieda obalu nad ukazovateľom s operátorom ako * a -> preťažený. Objekty triedy inteligentných ukazovateľov vyzerajú ako normálne ukazovatele. Ale na rozdiel od Normálne ukazovatele, môže uvoľniť a uvoľniť pamäť zničeného objektu.
Myšlienkou je absolvovať triedu s ukazovateľom, ničiteľ, a preťažení operátori ako * a -> . Keďže deštruktor sa automaticky volá, keď objekt prekročí rozsah, dynamicky alokovaná pamäť sa automaticky vymaže (alebo sa môže znížiť počet odkazov).
Príklad:
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;> }> |
Výkon
20
Rozdiel medzi ukazovateľmi a inteligentnými ukazovateľmi
| Ukazovateľ | Inteligentný ukazovateľ |
|---|---|
| Ukazovateľ je premenná, ktorá uchováva adresu pamäte, ako aj informácie o type údajov o tomto mieste v pamäti. Ukazovateľ je premenná, ktorá ukazuje na niečo v pamäti. | Je to objekt alokovaný zásobníkom na obalenie ukazovateľa. Inteligentné ukazovatele, v jednoduchosti, sú triedy, ktoré obalujú ukazovateľ alebo ukazovatele s rozsahom. |
| Nie je zničená v žiadnej forme, keď sa dostane mimo jej rozsah | Zničí sa, keď sa dostane mimo svoj rozsah |
| Ukazovatele nie sú také efektívne, pretože nepodporujú žiadnu inú funkciu. | Inteligentné ukazovatele sú efektívnejšie, pretože majú ďalšiu funkciu správy pamäte. |
| Sú veľmi zamerané na prácu/manuálne. | Sú svojou povahou automatické/predprogramované. |
Poznámka: Toto funguje len pre int . Takže budeme musieť vytvoriť inteligentný ukazovateľ pre každý objekt? Nie , existuje riešenie, Šablóna . V kóde nižšie, ako vidíte T môže byť akéhokoľvek typu.
Príklad:
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;> }> |
Výkon
20
Poznámka: Inteligentné ukazovatele sú tiež užitočné pri správe zdrojov, ako sú napríklad popisovače súborov alebo sieťové zásuvky.
Typy inteligentných ukazovateľov
Knižnice C++ poskytujú implementácie inteligentných ukazovateľov v nasledujúcich typoch:
- auto_ptr
- unique_ptr
- shared_ptr
- slabý_ptr
auto_ptr
Pomocou auto_ptr môžete spravovať objekty získané z nových výrazov a vymazať ich, keď je samotný auto_ptr zničený. Keď je objekt opísaný prostredníctvom auto_ptr, ukladá ukazovateľ na jeden alokovaný objekt.
Poznámka: Táto šablóna triedy je od C++ 11 zastaraná. unique_ptr je nové zariadenie s podobnou funkcionalitou, ale s vylepšeným zabezpečením.
unique_ptr
unique_ptr ukladá iba jeden ukazovateľ. Odstránením aktuálneho objektu z ukazovateľa môžeme priradiť iný objekt.
Príklad:
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; }> |
Výkon
50 50
shared_ptr
Používaním shared_ptr viac ako jeden ukazovateľ môže ukazovať na tento jeden objekt naraz a bude udržiavať a Referenčné počítadlo pomocou use_count() metóda.
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; }> |
Výkon
50 50 50 2
slabý_ptr
Weak_ptr je inteligentný ukazovateľ, ktorý obsahuje odkaz na objekt, ktorý nevlastní. Oveľa viac sa podobá shared_ptr okrem toho, že nezachová a Referenčné počítadlo . V tomto prípade ukazovateľ nebude mať na objekte pevnosť. Dôvodom je, že ak predpokladajme, že ukazovatele držia objekt a žiadajú o ďalšie objekty, môžu tvoriť a Zablokovanie.
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; }> |
Výkon
50 1
Knižnice C++ poskytujú implementáciu inteligentných ukazovateľov vo forme auto_ptr, unique_ptr, shared_ptr a Slabý_ptr