Chytrý ukazatel - Smart pointer
![]() | tento článek potřebuje další citace pro ověření.Červen 2015) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) ( |
v počítačová věda, a inteligentní ukazatel je abstraktní datový typ který simuluje a ukazatel a zároveň poskytuje další funkce, například automatické správa paměti nebo kontrola mezí. Účelem těchto funkcí je snížit chyby způsobené zneužitím ukazatelů při zachování účinnosti. Inteligentní ukazatele obvykle sledují paměť, na kterou ukazují, a lze je také použít ke správě dalších zdrojů, jako jsou síťová připojení a popisovače souborů. Inteligentní ukazatele byly nejprve popularizovány v programovacím jazyce C ++ během první poloviny 90. let jako vyvrácení kritiky nedostatku C ++ automatický sběr odpadu.[1][2]
Zneužití ukazatele může být hlavním zdrojem chyb. Inteligentní ukazatele zabraňují většině situací úniky paměti automatickým uvolněním paměti. Obecněji řečeno, dělají ničení předmětů automaticky: objekt ovládaný inteligentním ukazatelem je automaticky zničen (dokončeno a poté uvolnit), když je zničen poslední (nebo jediný) vlastník objektu, například proto, že vlastníkem je místní proměnná, a provádění ponechá proměnnou rozsah. Chytré ukazatele také eliminují visící ukazatele odložením zničení, dokud se objekt již nepoužívá.
Pokud jazyk podporuje automatický sběr odpadu (například Jáva nebo C# ), pak jsou inteligentní ukazatele nepotřebné pro rekultivaci a bezpečnostní aspekty správy paměti, přesto jsou užitečné pro jiné účely, například mezipaměti správa datové struktury pobytu a řízení zdrojů předmětů jako např úchyty pilníků nebo síťové zásuvky.
Existuje několik typů inteligentních ukazatelů. Někteří pracují s počítání referencí, ostatní přiřazením vlastnictví objektu jednomu ukazateli.
Dějiny
Přestože C ++ popularizoval koncept inteligentních ukazatelů, zejména započítána reference variety, bezprostřední předchůdce jednoho z jazyků, který inspiroval design C ++, měl do jazyka zabudované odkazy počítané do referencí. C ++ byl částečně inspirován Simula67.[3] Předchůdcem Simula67 byla Simula I. Pokud jde o Simulu I. živel je analogický s ukazatelem C ++ bez nula, a pokud je proces Simula I s fiktivním prohlášením, protože její tělo činnosti je analogické s C ++ struktur (což je analogické s C.A.R. Hoare záznam V tehdejší současné práci 60. let), Simula I měl referenční počítané prvky (tj. ukazatele-výrazy, které uchovávají nepřímý chod) na procesy (tj. záznamy) nejpozději do září 1965, jak je uvedeno v níže citovaných odstavcích.[4]
Na procesy lze odkazovat jednotlivě. Fyzicky je odkaz na proces ukazatel na oblast paměti obsahující data lokální pro proces a některé další informace definující jeho aktuální stav provádění. Z důvodů uvedených v části 2.2 jsou však odkazy na procesy vždy nepřímé, prostřednictvím volaných položek elementy. Formálně je odkaz na proces hodnotou výrazu typu živel.
…
živel hodnoty lze ukládat a načítat pomocí přiřazení a odkazů na živel proměnnými a jinými prostředky.
Jazyk obsahuje mechanismus pro zpřístupnění atributů procesu zvenčí, tj. Zevnitř jiných procesů. Tomu se říká vzdálený přístup. Proces je tedy odkazovatelná datová struktura.Stojí za povšimnutí podobnosti mezi procesem, jehož aktivním tělem je fiktivní prohlášení, a konceptem záznamu, který nedávno navrhli C. A. R. Hoare a N. Wirth
Protože si C ++ vypůjčil Simula přístup k alokaci paměti - Nový klíčové slovo při přidělování procesu / záznamu k získání nového živel k tomuto procesu / záznamu - není divu, že C ++ nakonec vzkřísil simulovský mechanismus inteligentního ukazatele s počítáním referencí uvnitř živel také.
Funkce
v C ++, inteligentní ukazatel je implementován jako třída šablony, která napodobuje pomocí přetížení operátora, chování tradičního (surový) ukazatel, (např. dereferencování, přiřazení) a zároveň poskytuje další funkce správy paměti.
Inteligentní ukazatele mohou usnadnit úmyslné programování vyjádřením typu, jak bude spravována paměť referenta ukazatele. Například pokud funkce C ++ vrátí ukazatel, neexistuje způsob, jak zjistit, zda by volající měl odstranit paměť referenta, když je volající hotový s informacemi.
SomeType* Dvojznačná funkce(); // Co by mělo být provedeno s výsledkem?
K vyřešení nejednoznačnosti se tradičně používají konvence pojmenování,[5] což je přístup náchylný k chybám a náročné na práci. C ++ 11 představil způsob, jak v tomto případě zajistit správnou správu paměti deklarováním funkce pro návrat a unique_ptr
,
std::unique_ptr<SomeType> Zjevná funkce();
Deklarace návratového typu funkce jako a unique_ptr
výslovně vysvětluje skutečnost, že volající převezme vlastnictví výsledku, a běhový modul C ++ zajistí, že paměť bude získána automaticky. Před C ++ 11, unique_ptr lze nahradit auto_ptr.
Vytváření nových objektů
Pro usnadnění přidělení a
std::shared_ptr<SomeType>
C ++ 11 zavedeno:
auto s = std::make_shared<SomeType>(konstruktor, parametry, tady);
a podobně
std::unique_ptr<some_type>
Od té doby C ++ 14 lze použít:
auto u = std::make_unique<SomeType>(konstruktor, parametry, tady);
Je upřednostňováno, téměř za všech okolností, používat tato zařízení přes internet Nový
klíčové slovo:[6]
unique_ptr
C ++ 11 zavádí std :: unique_ptr
, definované v záhlaví <memory>
.[7]
A unique_ptr
je kontejner pro surový ukazatel, který unique_ptr
se říká, že vlastní. A unique_ptr
výslovně brání kopírování jeho obsaženého ukazatele (jak by se stalo při normálním přiřazení), ale std :: tah
Tuto funkci lze použít k přenosu vlastnictví obsaženého ukazatele na jiný unique_ptr
. A unique_ptr
nelze kopírovat, protože jeho konstruktor kopírování a operátory přiřazení jsou výslovně odstraněny.
std::unique_ptr<int> p1(Nový int(5));std::unique_ptr<int> p2 = p1; // Chyba kompilace.std::unique_ptr<int> p3 = std::hýbat se(p1); // Převádí vlastnictví. p3 nyní vlastní paměť a p1 je nastaven na nullptr.p3.resetovat(); // Vymaže paměť.p1.resetovat(); // Nic nedělá.
std ::auto_ptr
je zastaralé pod C ++ 11 a zcela odstraněn z C ++ 17. Konstruktor kopírování a operátory přiřazení auto_ptr
nekopírujte uložený ukazatel. Místo toho oni přeneste to, opouští předchozí auto_ptr
objekt prázdný. To byl jeden způsob, jak implementovat přísné vlastnictví, takže pouze jeden auto_ptr
objekt může vlastnit ukazatel kdykoli. Tohle znamená tamto auto_ptr
by se nemělo používat tam, kde je potřeba sémantika kopírování.[8][Citace je zapotřebí ] Od té doby auto_ptr
již existoval s jeho sémantikou kopírování, nemohl být upgradován na ukazatel pouze pro pohyb bez porušení zpětná kompatibilita se stávajícím kódem.
C ++ 11 představuje std :: shared_ptr
a std :: slabá_ptr
, definované v záhlaví <memory>
.[7] C ++ 11 také představuje std :: make_shared
(std :: make_unique
byl zaveden v C ++ 14) k bezpečnému přidělení dynamické paměti v RAII paradigma.[9]
A shared_ptr
je kontejner pro a surový ukazatel. Tvrdí to počítání referencí vlastnictví jeho obsaženého ukazatele ve spolupráci se všemi kopiemi shared_ptr
. Objekt odkazovaný obsaženým surovým ukazatelem bude zničen tehdy a jen tehdy, když budou všechny jeho kopie shared_ptr
byly zničeny.
std::shared_ptr<int> p0(Nový int(5)); // Platné, přidělí 1 celé číslo a inicializuje ho hodnotou 5.std::shared_ptr<int[]> p1(Nový int[5]); // Platné, přiděluje 5 celých čísel.std::shared_ptr<int[]> p2 = p1; // Oba nyní vlastní paměť.p1.resetovat(); // Paměť stále existuje, kvůli p2.p2.resetovat(); // Uvolní paměť, protože ji nikdo jiný nevlastní.
A slabý_ptr
je kontejner pro surový ukazatel. Je vytvořen jako kopie a shared_ptr
. Existence nebo zničení slabý_ptr
kopie a shared_ptr
nemají žádný vliv na shared_ptr
nebo jeho další kopie. Po všech kopiích a shared_ptr
byly zničeny, všechny slabý_ptr
kopie se vyprázdní.
std::shared_ptr<int> p1 = std::make_shared<int>(5);std::slabý_ptr<int> wp1 {p1}; // p1 vlastní paměť.{ std::shared_ptr<int> p2 = wp1.zámek(); // Nyní p1 a p2 vlastní paměť. // p2 je inicializován ze slabého ukazatele, takže musíte zkontrolovat, zda // paměť stále existuje! -li (p2) { DoSomethingWith(p2); }}// p2 je zničen. Paměť je vlastněna p1.p1.resetovat(); // Uvolněte paměť.std::shared_ptr<int> p3 = wp1.zámek(); // Paměť je pryč, takže dostaneme prázdný shared_ptr.-li (p3) { // kód se nespustí ActionThatNeedsALivePointer(p3);}
Protože implementace shared_ptr
používá počítání referencí, kruhové odkazy jsou potenciálně problém. Kruhový shared_ptr
řetězec lze přerušit změnou kódu tak, aby jeden z odkazů byl a slabý_ptr
.
Více vláken může bezpečně současně přistupovat k různým shared_ptr
a slabý_ptr
objekty, které ukazují na stejný objekt.[10]
Aby bylo zajištěno, musí být odkazovaný objekt chráněn samostatně bezpečnost nití.
shared_ptr
a slabý_ptr
jsou založeny na verzích používaných Posilujte knihovny.[Citace je zapotřebí ] C ++ technická zpráva 1 (TR1) je nejprve představil standardu, as obecné nástroje, ale C ++ 11 přidává další funkce v souladu s verzí Boost.
Viz také
- Automatické počítání referencí
- Získávání zdrojů je inicializace (RAII)
- auto_ptr
- Neprůhledný ukazatel
- Reference (informatika)
- Boost (knihovny C ++)
- Tlustý ukazatel
- Sběr odpadu v počítačovém programování
Reference
- ^ Kline, Marshall (září 1997). „Sekce C ++ Často kladené otázky Lite o inteligentních ukazatelích počítaných jako reference a referenční sémantice kopírování při zápisu v Častých dotazech na správu bezplatného úložiště“. cis.usouthal.edu. Citováno 6. dubna 2018.
- ^ Colvin, Gregory (1994). "návrh na standardizaci countted_ptr ve standardní knihovně C ++" (PDF). open-std.org. Citováno 6. dubna 2018.
- ^ Stroustrup, Bjarne. „Historie C ++: 1979–1991“ (PDF). Citováno 6. dubna 2018.
- ^ Dahl, Ole-Johan a Nygaard, Kristen (září 1966). „SIMULA - simulační jazyk založený na ALGOLU“ (PDF). folk.uio.č. Citováno 6. dubna 2018.CS1 maint: více jmen: seznam autorů (odkaz)
- ^ „Příručka Taligent k navrhování programů, část Používejte speciální názvy pro kopírování, vytváření a přijímání rutin“.
- ^ Sutter, Herb (20. dubna 2013). „Trip report: ISO C ++ Spring 2013 Meeting“. isocpp.org. Citováno 14. června 2013.
- ^ A b ISO 14882: 2011 20.7.1
- ^ Standard bezpečného kódování CERT C ++
- ^ ISO 14882: 2014 20.7.1
- ^ boost :: shared_ptr bezpečnost vlákna (formálně nepokrývá std :: shared_ptr, ale předpokládá se, že má stejná omezení vláken)
Další čtení
- Scott Meyers (2014). Efektivní moderní C ++. Sebastopol, CA: O'Reilly Media. ISBN 978-1491903995. OCLC 884480640.
externí odkazy
- Chytré ukazatele. Moderní design v C ++: Použité obecné programovací a návrhové vzory podle Andrei Alexandrescu, Addison-Wesley, 2001.
- countptr.hpp. Standardní knihovna C ++ - výuka a reference podle Nicolai M. Josuttis
- Zvyšte inteligentní ukazatele
- Nový C ++: Chytré ukazatele. Herb Sutter 1. srpna 2002
- Inteligentní ukazatele - co, proč, které?. Yonat Sharon
- Přehled inteligentních ukazatelů. John M. Dlugosz
- Chytré ukazatele v Delphi
- Chytré ukazatele v rezu
- Inteligentní ukazatele v moderním C ++