Indicator inteligent

Versiunea actuală a paginii nu a fost încă examinată de colaboratori experimentați și poate diferi semnificativ de versiunea revizuită pe 22 martie 2021; verificările necesită 17 modificări .

Un  pointer inteligent este o expresie de direcție a memoriei care este utilizată pe scară largă atunci când programați în limbaje de nivel înalt precum C++ , Rust și așa mai departe. De regulă, este implementat ca o clasă specializată (de obicei parametrizată ), care imită interfața unui pointer obișnuit și adaugă funcționalitatea nouă necesară (de exemplu, verificarea limitelor la acces sau curățarea memoriei ) [1] .

În mod obișnuit, scopul principal al utilizării indicatoarelor inteligente este de a încapsula gestionarea dinamică a memoriei în așa fel încât proprietățile și comportamentul pointerilor inteligente să imite proprietățile și comportamentul pointerilor obișnuiți. În același timp, aceștia sunt responsabili pentru eliberarea în timp util și precisă a resurselor alocate, ceea ce simplifică procesul de dezvoltare a codului și depanare, eliminând pierderile de memorie și apariția legăturilor suspendate [2] .

Indicatori de proprietate partajată (cu numărarea referințelor)

Acestea sunt utilizate în mod obișnuit cu obiectele care au operații speciale „mărește numărul de referințe” ( AddRef()în COM ) și „reduce numărul de referințe” ( Release()în COM). Cel mai adesea, astfel de obiecte sunt moștenite dintr-o clasă sau interfață specială (de exemplu, IUnknownîn COM).

Când apare o nouă referință la un obiect, se apelează operația „creșterea numărului de referințe”, iar când este distrusă, se apelează operația „scăderea numărului de referințe”. Dacă, ca urmare a operației „reducere referințe”, numărul de referințe la un obiect devine zero, atunci obiectul este șters.

Această tehnică se numește numărare automată a referințelor . Se potrivește numărul de pointeri care stochează adresa obiectului cu numărul de referințe stocate în obiect, iar când acest număr ajunge la zero, face ca obiectul să fie șters. Avantajele sale sunt fiabilitatea relativ ridicată, viteza și ușurința de implementare în C++ . Dezavantajul este că devine mai dificil de utilizat în cazul referințelor circulare (necesitatea de a folosi „referințe slabe”).

Implementări

Există două tipuri de astfel de indicatoare: cu stocare contor în interiorul obiectului și cu stocare contor în exterior.

Cea mai simplă opțiune este de a stoca contorul în interiorul unui obiect gestionat. În COM , obiectele numărate cu referințe sunt implementate după cum urmează:

Implementat în același mod boost::intrusive_ptr.

Contoarele de std::shared_ptrreferință sunt stocate în afara obiectului, într-o structură specială de date. Un astfel de indicator inteligent este de două ori mai mare decât unul standard (are două câmpuri, unul indică structura contorului, al doilea spre obiectul gestionat). Acest design permite:

Deoarece structura contorului este mică, aceasta poate fi alocată, de exemplu, prin pool-ul de obiecte .

Problema referințelor circulare

Să presupunem că există două obiecte și fiecare dintre ele are un pointer propriu. Pointerului din primul obiect i se atribuie adresa celui de-al doilea obiect, iar pointerului din al doilea este adresa primului obiect. Dacă acum tuturor pointerii externi (adică nu sunt stocați în interiorul acestor obiecte) către două obiecte date li se atribuie noi valori, atunci pointerii din interiorul obiectelor se vor deține unul pe celălalt și vor rămâne în memorie. Ca urmare, va exista o situație în care obiectele nu pot fi accesate, adică o scurgere de memorie .

Problema referințelor circulare este rezolvată fie prin proiectarea adecvată a structurilor de date, fie prin utilizarea colectării gunoiului , fie prin utilizarea a două tipuri de referințe: puternice (deținând) și slabe (nedeținând, de exemplu std::weak_ptr).

Exemple de implementare

Marcatori de proprietate individuală

Adesea, indicatorii de proprietate partajată sunt prea mari și „grele” pentru sarcinile programatorului: de exemplu, trebuie să creați un obiect de unul dintre tipurile N, să-l dețineți, să accesați din când în când funcțiile sale virtuale și apoi să îl ștergeți corect. Pentru a face acest lucru, utilizați „fratele mai mic” - un indicator al proprietății unice.

Astfel de indicatori atunci când atribuie o nouă valoare sau se șterg singuri șterg obiectul. Atribuirea pointerilor de proprietate individuală este posibilă numai cu distrugerea unuia dintre pointeri - astfel, nu va exista niciodată o situație ca doi pointeri să dețină același obiect.

Dezavantajul lor este dificultatea de a trece un obiect din sfera indicatorului.

Exemple de implementare

Indicatori către bufferul de memorie al altcuiva

În cele mai multe cazuri, dacă există o funcție care se ocupă de o matrice, se scrie unul din două lucruri:

void sort ( size_t size , int * data ); // pointer + size void sort ( std :: vector < int >& data ); // structură specifică a memoriei

Prima exclude verificarea automată a intervalului. Al doilea limitează aplicabilitatea std::vectorlui și nu puteți sorta, de exemplu, un șir dintr-o matrice sau o parte a altuia vector.

Prin urmare, în bibliotecile dezvoltate pentru funcții care folosesc bufferele de memorie ale altor persoane, acestea folosesc tipuri de date „ușoare” precum

șablon < classT > _ struct Buf1d { T * date ; size_t dimensiune ; Buf1d ( std :: vector < T >& vec ); T & operator []( size_t i ); };

Folosit adesea pentru șiruri de caractere: analizarea , rularea unui editor de text și alte sarcini specifice au nevoie de propriile structuri de date care sunt mai rapide decât metodele standard de manipulare a șirurilor.

Exemple de implementare

  • bibliotecă de șabloane standard: std::string_view, std::span.
  • Qt: QStringView.

Note

  1. Alger D. Indicatori inteligenti ca idiom // C++. Biblioteca programatorului . - 1999. - S. 75. - 320 p. — ISBN 0-12-049942-8 . Arhivat pe 12 iulie 2018 la Wayback Machine
  2. Ivor Horton, Peter Van Weert. Indicatori bruti și indicatori inteligenti // Începând cu C++17. De la novice la profesionist. - a 5-a. - Apress, 2018. - P. 206. - ISBN 978-1-4842-3365-8 .

Link -uri