Ä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] .
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").
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 .
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).
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.
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 muistirakenneEnsimmä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.