Älykäs osoitin

Kokeneet kirjoittajat eivät ole vielä tarkistaneet sivun nykyistä versiota, ja se voi poiketa merkittävästi 22. maaliskuuta 2021 tarkistetusta versiosta . tarkastukset vaativat 17 muokkausta .

Älykäs osoitin on muistin epäsuora idiomi, jota käytetään  laajalti ohjelmoitaessa korkean tason kielillä, kuten C++ , Rust ja niin edelleen. Pääsääntöisesti se toteutetaan erikoisluokkana ( yleensä parametroituna ), joka jäljittelee tavallisen osoittimen käyttöliittymää ja lisää tarvittavat uudet toiminnot (esim. pääsyn rajojen tarkistus tai muistin puhdistus ) [1] .

Tyypillisesti älykkäiden osoittimien käytön päätarkoitus on kapseloida dynaaminen muistin käsittely siten, että älykkäiden osoittimien ominaisuudet ja käyttäytyminen jäljittelevät tavallisten osoittimien ominaisuuksia ja käyttäytymistä. Samalla he ovat vastuussa allokoitujen resurssien oikea-aikaisesta ja tarkasta vapauttamisesta, mikä yksinkertaistaa koodin kehitys- ja virheenkorjausprosessia, eliminoi muistivuodot ja roikkuvien linkkien esiintymisen [2] .

Jaetun omistajuuden osoittimet (viitteiden laskentaan)

Näitä käytetään yleisesti objekteissa, joilla on erikoistoiminnot "lisää viitemäärää" ( COMAddRef() :ssa ) ja "pienennä viitemäärää" ( COMissa). Useimmiten tällaiset objektit peritään erityisestä luokasta tai rajapinnasta (esimerkiksi COM:ssa). Release()IUnknown

Kun uusi viittaus objektiin ilmestyy, kutsutaan "lisää viittausten määrää" -operaatiota ja kun se tuhotaan, kutsutaan "pienennä viittausten määrää" -toimintoa. Jos "vähennä viittauksia" -toiminnon seurauksena viittausten määrä objektiin on nolla, objekti poistetaan.

Tätä tekniikkaa kutsutaan automaattiseksi viitelaskentaksi . Se vastaa objektin osoitteen tallentavien osoittimien määrää objektiin tallennettujen viitteiden määrään, ja kun tämä luku saavuttaa nollan, objekti poistetaan. Sen etuja ovat suhteellisen korkea luotettavuus, nopeus ja helppokäyttöisyys C++ :ssa . Haittapuolena on, että sen käyttö vaikeutuu pyöreissä viittauksissa (tarve käyttää "heikkoja viittauksia").

Toteutukset

Tällaisia ​​osoittimia on kahta tyyppiä: tiskillä on objektin sisällä ja laskurin ulkopuolella.

Yksinkertaisin vaihtoehto on tallentaa laskuri hallitun objektin sisään. COM : ssa viittauksilla lasketut objektit toteutetaan seuraavasti:

Toteutettu samalla tavalla boost::intrusive_ptr.

Referenssilaskurit std::shared_ptron tallennettu objektin ulkopuolelle erityiseen tietorakenteeseen. Tällainen älykäs osoitin on kaksi kertaa suurempi kuin tavallinen (sillä on kaksi kenttää, yksi osoittaa laskurirakenteeseen, toinen hallittavaan objektiin). Tämä muotoilu mahdollistaa:

Koska laskurirakenne on pieni, se voidaan allokoida esimerkiksi objektipoolin kautta .

Pyöreän viittauksen ongelma

Oletetaan, että on kaksi objektia ja jokaisella niistä on omistava osoitin. Ensimmäisen objektin osoittimelle on määritetty toisen objektin osoite, ja toisen kohteen osoitin on ensimmäisen objektin osoite. Jos nyt kaikille ulkoisille (eli ei ole tallennettu näiden objektien sisälle) osoittimille kahdelle tietylle objektille annetaan uudet arvot, objektien sisällä olevat osoittimet omistavat edelleen toisensa ja pysyvät muistissa. Seurauksena on tilanne, jossa esineisiin ei pääse käsiksi, eli muistivuoto .

Pyöreän viittauksen ongelma ratkaistaan ​​joko sopivalla tietorakenteiden suunnittelulla tai käyttämällä roskienkeruuta tai käyttämällä kahdenlaisia ​​viittauksia: vahva (omistava) ja heikko (ei-omistava, esimerkiksi std::weak_ptr).

Toteutusesimerkkejä

Yksinomainen elinkeinonharjoittaja

Usein jaetun omistajuuden osoittimet ovat liian suuria ja "raskaita" ohjelmoijan tehtäviin: sinun on esimerkiksi luotava jokin N-tyypistä objekti, omistettava se, käytettävä sen virtuaalisia toimintoja ajoittain ja poistettava se sitten oikein. Käytä tätä varten "pikkuveli" - indikaattori yksinomaisesta omistuksesta.

Tällaiset osoittimet uuden arvon määrittämisen tai itsensä poistamisen yhteydessä poistavat kohteen. Yksityisyritysosoittimien antaminen on mahdollista vain yhden osoittimien tuhoutuessa - näin ei koskaan tule tilannetta, että kaksi osoittimia omistaisi saman kohteen.

Niiden haittana on vaikeus siirtää esinettä osoittimen soveltamisalan ulkopuolelle.

Toteutusesimerkkejä

Osoittimet jonkun toisen muistipuskuriin

Useimmissa tapauksissa, jos on funktio, joka käsittelee taulukkoa, kirjoitetaan toinen kahdesta asiasta:

void sort ( koko_t koko , int * data ); // osoitin + koko void sort ( std :: vektori < int >& data ); // tietty muistirakenne

Ensimmäinen sulkee pois automaattisen etäisyyden tarkistuksen. Toinen rajoittaa std::vector's:n sovellettavuutta, etkä voi lajitella esimerkiksi taulukon merkkijonoa tai toisen osan merkkijonoa vector.

Siksi kehitetyissä kirjastoissa funktioille, jotka käyttävät muiden ihmisten muistipuskureita, ne käyttävät "kevyitä" tietotyyppejä, kuten

malli < luokkaT > _ struct Buf1d { T * data ; koko_t koko ; Buf1d ( std :: vektori < T >& vec ); T & operaattori []( koko_t i ); };

Käytetään usein merkkijonoille: jäsentäminen , tekstieditorin käyttäminen ja muut erityiset tehtävät tarvitsevat omat tietorakenteet, jotka ovat nopeampia kuin tavalliset merkkijonojen käsittelymenetelmät.

Toteutusesimerkkejä

  • vakiomallikirjasto: std::string_view, std::span.
  • Qt: QStringView.

Muistiinpanot

  1. Alger D. Älykkäät osoittimet idioomana // C++. Ohjelmoijan kirjasto . - 1999. - S. 75. - 320 s. — ISBN 0-12-049942-8 . Arkistoitu 12. heinäkuuta 2018 Wayback Machineen
  2. Ivor Horton, Peter Van Weert. Raaka-osoittimet ja älykkäät osoittimet // Alku C++17. Aloittelijasta ammattilaiseksi. - 5. - Apress, 2018. - S. 206. - ISBN 978-1-4842-3365-8 .

Linkit