Inteligentní ukazatele v C++
Předpoklad: Ukazatele v C++
Ukazatele se používají pro přístup ke zdrojům, které jsou externí vůči programu – jako je haldová paměť. Takže pro přístup k paměti haldy (pokud je něco vytvořeno v paměti haldy) se používají ukazatele. Při přístupu k jakémukoli externímu zdroji používáme pouze kopii zdroje. Pokud v něm provedeme nějaké změny, změníme ho pouze v zkopírované verzi. Pokud však použijeme ukazatel na zdroj, budeme moci změnit původní zdroj.
Problémy s normálními ukazateli
Některé problémy s normálními ukazateli v C++ jsou následující:
- Netěsnosti paměti: K tomu dochází, když je paměť opakovaně alokována programem, ale nikdy není uvolněna. To vede k nadměrné spotřebě paměti a nakonec vede ke zhroucení systému. Visící ukazatele: Visutý ukazatel je ukazatel, ke kterému dochází v době, kdy je objekt uvolněn z paměti, aniž by se změnila hodnota ukazatele. Divoké ukazatele: Divoké ukazatele jsou ukazatele, které jsou deklarovány a přiděleny paměti, ale ukazatel není nikdy inicializován, aby ukazoval na jakýkoli platný objekt nebo adresu. Nekonzistence dat: Nekonzistence dat nastává, když jsou některá data uložena v paměti, ale nejsou aktualizována konzistentním způsobem. Přetečení vyrovnávací paměti: Když se ukazatel používá k zápisu dat na adresu paměti, která je mimo alokovaný paměťový blok. To vede k poškození dat, která mohou zneužít zákeřní útočníci.
Pří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ýstup
Memory limit exceeded
Vysvětlení: Ve funkci zábava , vytvoří ukazatel, který ukazuje na Obdélník objekt. Objekt Obdélník obsahuje dvě celá čísla, délka, a šířka . Když funkce zábava skončí, p bude zničen, protože jde o lokální proměnnou. Paměť, kterou spotřebovala, však nebude uvolněna, protože jsme ji zapomněli použít odstranit p; na konci funkce. To znamená, že paměť nebude volná pro použití jinými zdroji. Ale už nepotřebujeme proměnnou, potřebujeme paměť.
ve funkci, hlavní , zábava se volá v nekonečné smyčce. To znamená, že bude tvořit dál p . Bude alokovat stále více paměti, ale neuvolní je, protože jsme ji nepřidělili. Promarněnou paměť nelze znovu použít. Což je únik paměti. Celá halda paměť může být z tohoto důvodu nepoužitelná.
Inteligentní ukazatele
Jak jsme věděli, nevědomé neudělení ukazatele způsobí únik paměti, který může vést ke zhroucení programu. Jazyky Java, C# má Mechanismy sběru odpadků chytře uvolnit nevyužitou paměť k opětovnému použití. Programátor se nemusí obávat žádných úniků paměti. C++ přichází s vlastním mechanismem, který je Chytrý ukazatel . Když je objekt zničen, uvolní se také paměť. Nemusíme to tedy mazat, protože to zvládne Smart Pointer.
A Chytrý ukazatel je třída obalu nad ukazatelem s operátorem jako * a -> přetížené. Objekty třídy inteligentních ukazatelů vypadají jako normální ukazatele. Ale na rozdíl od Normální ukazatele, může uvolnit a uvolnit paměť zničených objektů.
Cílem je vzít třídu s ukazatelem, ničitel, a přetížení operátoři jako * a -> . Vzhledem k tomu, že destruktor je automaticky volán, když objekt překročí rozsah, dynamicky alokovaná paměť bude automaticky odstraněna (nebo může být snížen počet odkazů).
Pří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ýstup
20
Rozdíl mezi ukazateli a inteligentními ukazateli
| Ukazatel | Chytrý ukazatel |
|---|---|
| Ukazatel je proměnná, která udržuje adresu paměti a také informace o datovém typu o tomto umístění v paměti. Ukazatel je proměnná, která ukazuje na něco v paměti. | Jedná se o objekt alokovaný do zásobníku. Inteligentní ukazatele, jednoduše řečeno, jsou třídy, které obalují ukazatel nebo ukazatele s rozsahem. |
| Není zničena v žádné formě, když se dostane mimo její rozsah | Zničí se, když se dostane mimo svůj rozsah |
| Ukazatele nejsou tak efektivní, protože nepodporují žádnou jinou funkci. | Inteligentní ukazatele jsou efektivnější, protože mají další funkci správy paměti. |
| Jsou velmi pracovně/manuální. | Jsou svou povahou automatické/předprogramované. |
Poznámka: Toto funguje pouze pro int . Takže budeme muset vytvořit Smart Ukazatel pro každý objekt? Ne , existuje řešení, Šablona . V kódu níže, jak vidíte T může být jakéhokoli typu.
Pří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ýstup
20
Poznámka: Inteligentní ukazatele jsou také užitečné při správě zdrojů, jako jsou popisovače souborů nebo síťové zásuvky.
Typy inteligentních ukazatelů
Knihovny C++ poskytují implementace inteligentních ukazatelů v následujících typech:
- auto_ptr
- unique_ptr
- shared_ptr
- slabý_ptr
auto_ptr
Pomocí auto_ptr můžete spravovat objekty získané z nových výrazů a mazat je, když je auto_ptr zničeno. Když je objekt popsán pomocí auto_ptr, ukládá ukazatel na jeden přidělený objekt.
Poznámka: Tato šablona třídy je od C++11 zastaralá. unique_ptr je nové zařízení s podobnou funkčností, ale s vylepšeným zabezpečením.
unique_ptr
unique_ptr ukládá pouze jeden ukazatel. Jiný objekt můžeme přiřadit odstraněním aktuálního objektu z ukazatele.
Pří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ýstup
50 50
shared_ptr
Používáním shared_ptr více než jeden ukazatel může ukazovat na tento jeden objekt najednou a bude udržovat a Referenční počítadlo za použití use_count() 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; }> |
Výstup
50 50 50 2
slabý_ptr
Weak_ptr je inteligentní ukazatel, který obsahuje odkaz na objekt, který nevlastní. Je mnohem podobnější sdílenému_ptr kromě toho, že nebude udržovat a Referenční počítadlo . V tomto případě nebude mít ukazatel na objektu pevnost. Důvodem je, že pokud předpokládejme, že ukazatele drží objekt a požadují další objekty, mohou tvořit a Zablokování.
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ýstup
50 1
Knihovny C++ poskytují implementace inteligentních ukazatelů ve formě auto_ptr, unique_ptr, shared_ptr a slabé_ptr