Okos mutató

Az oldal jelenlegi verzióját még nem ellenőrizték tapasztalt közreműködők, és jelentősen eltérhet a 2021. március 22-én felülvizsgált verziótól ; az ellenőrzések 17 szerkesztést igényelnek .

Az  intelligens mutató egy memória indirekt idióma, amelyet széles körben használnak magas szintű nyelveken, például C++ , Rust és így tovább. Általában speciális osztályként valósítják meg (általában paraméterezett ), amely egy normál mutató interfészét utánozza , és hozzáadja a szükséges új funkciókat (például hozzáférési határellenőrzés vagy memóriatisztítás ) [1] .

Az intelligens mutatók használatának fő célja általában a dinamikus memóriakezelés olyan módon történő beágyazása , hogy az intelligens mutatók tulajdonságai és viselkedése utánozzák a normál mutatók tulajdonságait és viselkedését . Ugyanakkor felelősek az allokált erőforrások időbeni és pontos felszabadításáért, ami leegyszerűsíti a kódfejlesztési és hibakeresési folyamatot, kiküszöböli a memóriaszivárgást és a lógó linkek előfordulását [2] .

Megosztott tulajdonjogi mutatók (hivatkozások számlálásával)

Ezeket általában olyan objektumoknál használják, amelyek speciális műveletekkel rendelkeznek: „Referenciaszám növelése” ( COMAddRef() -ban ) és „Referenciaszám csökkentése” ( COM-ban). Leggyakrabban az ilyen objektumok egy speciális osztályból vagy interfészből öröklődnek (például a COM-ban). Release()IUnknown

Ha új hivatkozás jelenik meg egy objektumra, akkor a „hivatkozások számának növelése” műveletet hívják meg, ha pedig megsemmisül, a „hivatkozások számának csökkentése” műveletet hívják meg. Ha a "hivatkozások csökkentése" művelet eredményeként egy objektumra mutató hivatkozások száma nulla lesz, akkor az objektum törlődik.

Ezt a technikát automatikus referenciaszámlálásnak nevezik . Összeegyezteti az objektum címét tároló mutatók számát az objektumban tárolt hivatkozások számával, és ha ez a szám eléri a nullát, az objektum törlését okozza. Előnye a viszonylag nagy megbízhatóság, a gyorsaság és a könnyű implementáció C++ nyelven . Hátránya, hogy körkörös hivatkozások esetén nehezebben használható ("gyenge hivatkozások" használatának szükségessége).

Megvalósítások

Az ilyen mutatóknak két típusa van: az objektumon belüli számlálótárolóval és kívüli pulttárolóval.

A legegyszerűbb lehetőség a számláló tárolása egy kezelt objektumon belül. A COM -ban a referencia-számlálású objektumok a következőképpen valósulnak meg:

Ugyanúgy végrehajtva boost::intrusive_ptr.

A std::shared_ptrreferenciaszámlálók az objektumon kívül, speciális adatstruktúrában tárolódnak. Egy ilyen intelligens mutató kétszer akkora, mint egy szabványos (két mezője van, az egyik a számlálószerkezetre, a másik a kezelt objektumra mutat). Ez a kialakítás lehetővé teszi:

Mivel a számlálószerkezet kicsi, kiosztható például az objektumkészleten keresztül .

A körkörös hivatkozások problémája

Tegyük fel, hogy két objektum van, és mindegyiknek van egy tulajdonmutatója. Az első objektum mutatójához a második objektum címe van hozzárendelve, a másodikban lévő mutató pedig az első objektum címe. Ha most minden külső (vagyis nem ezekben az objektumokban tárolt) mutatóban két adott objektum új értéket kap, akkor az objektumok belsejében lévő mutatók továbbra is egymás tulajdonosai maradnak, és a memóriában maradnak. Ennek eredményeként olyan helyzet áll elő, amikor az objektumok nem érhetők el, azaz memóriaszivárgás .

A körkörös hivatkozások problémáját vagy az adatszerkezetek megfelelő kialakításával, vagy a szemétgyűjtéssel , vagy kétféle hivatkozás használatával oldjuk meg: erős (tulajdonos) és gyenge (például nem birtokló std::weak_ptr).

Megvalósítási példák

Egyéni vállalkozás jelzők

A megosztott tulajdonjog mutatói gyakran túl nagyok és „nehézek” a programozó feladataihoz: például létre kell hoznia egy N típusú objektumot, birtokolnia kell, időnként hozzá kell férnie a virtuális funkcióihoz, majd megfelelően törölnie kell. Ehhez használja a "kistestvért" - az egyedüli tulajdon mutatóját.

Az ilyen mutatók új érték hozzárendelésekor vagy önmaguk törlésekor törlik az objektumot. Egyéni vállalkozási mutatók hozzárendelése csak az egyik mutató megsemmisítésével lehetséges - így soha nem lesz olyan, hogy két mutató ugyanazt az objektumot birtokolja.

Hátrányuk az, hogy egy objektumot nehéz kihagyni a mutató hatóköréből.

Megvalósítási példák

Mutatók valaki más memóriapufferére

A legtöbb esetben, ha van egy függvény, amely egy tömböt kezel, két dolog egyikét írják le:

void sort ( size_t size , int * data ); // mutató + méret void rendezés ( std :: vektor < int >& adatok ); // specifikus memóriastruktúra

Az első kizárja az automatikus tartományellenőrzést. A második korlátozza a std::vector's alkalmazhatóságát, és nem lehet rendezni például egy tömb karakterláncát vagy egy másik tömb egy részét vector.

Ezért a mások memóriapuffereit használó függvények kifejlesztett könyvtáraiban „könnyű” adattípusokat használnak, mint pl.

sablon < classT > _ struct Buf1d { T * adat ; size_t size ; Buf1d ( std :: vektor < T >& vec ); T & operátor []( size_t i ); };

Gyakran használják karakterláncokhoz: az elemzéshez , a szövegszerkesztő futtatásához és más speciális feladatokhoz saját adatstruktúrákra van szükség, amelyek gyorsabbak, mint a szokásos karakterlánc-manipulációs módszerek.

Megvalósítási példák

  • szabványos sablonkönyvtár: std::string_view, std::span.
  • Qt: QStringView.

Jegyzetek

  1. Alger D. Intelligens mutatók, mint idióma // C++. Programozói Könyvtár . - 1999. - S. 75. - 320 p. — ISBN 0-12-049942-8 . Archiválva : 2018. július 12. a Wayback Machine -nél
  2. Ivor Horton, Peter Van Weert. Nyers mutatók és intelligens mutatók // C++17 kezdete. Kezdőtől profiig. - 5. - Apress, 2018. - P. 206. - ISBN 978-1-4842-3365-8 .

Linkek