Indicator inteligent - Smart pointer
În informatică , un indicator inteligent este un tip de date abstract care simulează un indicator în timp ce oferă caracteristici adăugate, precum gestionarea automată a memoriei sau verificarea limitelor . Astfel de caracteristici sunt menite să reducă erorile cauzate de utilizarea incorectă a indicatorilor, păstrând în același timp eficiența. Indicatoarele inteligente țin de obicei evidența memoriei către care indică și pot fi folosite și pentru gestionarea altor resurse, cum ar fi conexiunile de rețea și mânerele de fișiere. Indicatorii inteligenți au fost popularizați pentru prima dată în limbajul de programare C ++ în prima jumătate a anilor 1990 ca respingere a criticilor față de lipsa de colectare automată a gunoiului de către C ++ .
Utilizarea incorectă a indicatorului poate fi o sursă majoră de bug-uri. Indicatoarele inteligente previn majoritatea situațiilor de scurgeri de memorie, făcând automat repartizarea memoriei. Mai general, ele fac automat distrugerea obiectelor : un obiect controlat de un indicator inteligent este distrus automat ( finalizat și apoi repartizat) atunci când ultimul (sau singurul) proprietar al unui obiect este distrus, de exemplu, deoarece proprietarul este o variabilă locală și execuție lasă variabilei domeniul de aplicare . Indicatoarele inteligente elimină, de asemenea, indicatoarele suspendate, amânând distrugerea până când un obiect nu mai este utilizat.
Dacă un limbaj acceptă colectarea automată a deșeurilor (de exemplu, Java sau C # ), atunci indicatoarele inteligente nu sunt necesare pentru recuperarea și aspectele de siguranță ale gestionării memoriei, dar sunt utile pentru alte scopuri, cum ar fi gestionarea rezidenței structurii datelor cache și gestionarea resurselor obiectelor precum mânere de fișiere sau prize de rețea .
Există mai multe tipuri de indicatoare inteligente. Unele funcționează cu numărarea referințelor , altele atribuind dreptul de proprietate asupra unui obiect unui singur pointer.
Istorie
Chiar dacă C ++ a popularizat conceptul de indicatori inteligenți, în special varietatea cu referințe , predecesorul imediat al unuia dintre limbile care au inspirat designul C ++ a avut referințe cu referințe încorporate în limbaj. C ++ a fost inspirat parțial de Simula67. Strămoș Simula67 a fost Simula I. În măsura în care Simula I a elementului este analog C ++ e pointer fără nul , și în măsura în care procesul de Simula I cu un manechin-declarație ca organ activitate este analog cu C ++ 's struct (care în sine este analog cu CARHoare lui înregistrare în atunci -funcție contemporană din anii 1960), Simula I a făcut referire la elemente numărate (adică, expresii pointer care găzduiesc indirecție) la procese (adică înregistrări) până cel târziu în septembrie 1965, așa cum se arată în paragrafele citate de mai jos.
Procesele pot fi referite individual. Fizic, o referință de proces este un indicator către o zonă de memorie care conține datele locale procesului și câteva informații suplimentare care definesc starea sa actuală de execuție. Cu toate acestea, din motivele enunțate în secțiunea 2.2, referințele de proces sunt întotdeauna indirecte, prin elemente numite elemente. În mod formal, o referință la un proces este valoarea unei expresii de tip element .
… Valorile
elementelor pot fi stocate și recuperate prin alocări și referințe la variabilele elementului și prin alte mijloace.
Limbajul conține un mecanism pentru a face atributele unui proces accesibile din exterior, adică din alte procese. Aceasta se numește acces la distanță. Un proces este astfel o structură de date referențială.
Merită remarcat similaritatea dintre un proces al cărui corp de activitate este o afirmație falsă și conceptul de înregistrare propus recent de CAR Hoare și N. Wirth
Deoarece C ++ a împrumutat abordarea Simulei cu privire la alocarea memoriei - noul cuvânt cheie atunci când alocați un proces / înregistrare pentru a obține un element nou la acel proces / înregistrare - nu este surprinzător faptul că C ++ a înviat în cele din urmă mecanismul de pointer inteligent contorizat de referințe al Simulei în cadrul elementului ca bine.
Caracteristici
În C ++ , un pointer inteligent este implementat ca o clasă de șablon care imită, prin intermediul supraîncărcării operatorului , comportamentele unui pointer tradițional (brut) (de exemplu, dereferențierea, atribuirea) oferind în același timp caracteristici suplimentare de gestionare a memoriei.
Indicatoarele inteligente pot facilita programarea intenționată prin exprimarea, în tip, a modului în care va fi gestionată memoria referentului indicatorului. De exemplu, dacă o funcție C ++ returnează un pointer, nu există nicio modalitate de a ști dacă apelantul ar trebui să șteargă memoria referentului atunci când apelantul a terminat cu informațiile.
SomeType* AmbiguousFunction(); // What should be done with the result?
În mod tradițional, convențiile de numire au fost folosite pentru a rezolva ambiguitatea, care este o abordare predispusă la erori, care necesită multă muncă. C ++ 11 a introdus o modalitate de a asigura gestionarea corectă a memoriei în acest caz prin declararea funcției de returnare a unique_ptr,
std::unique_ptr<SomeType> ObviousFunction();
Declararea tipului de returnare a funcției unique_ptrexplicită faptul că apelantul își asumă rezultatul, iar timpul de execuție C ++ asigură că memoria va fi recuperată automat. Înainte de C ++ 11 , unique_ptr poate fi înlocuit cu auto_ptr .
Crearea de obiecte noi
Pentru a ușura alocarea unui
std::shared_ptr<SomeType>
C ++ 11 introdus:
auto s = std::make_shared<SomeType>(constructor, parameters, here);
și în mod similar
std::unique_ptr<some_type>
Din moment ce C ++ 14 se poate utiliza:
auto u = std::make_unique<SomeType>(constructor, parameters, here);
Este de preferat, în aproape toate circumstanțele, să folosiți aceste facilități peste newcuvântul cheie.
unique_ptr
C ++ 11 introduce std::unique_ptr, definit în antet <memory>.
A unique_ptreste un container pentru un indicator brut, pe care unique_ptrse spune că îl deține. O unique_ptrprevine în mod explicit copierea indicatorului său conținut (așa cum s-ar întâmpla cu atribuirea normală), dar std::movefuncția poate fi utilizată pentru a transfera dreptul de proprietate asupra indicatorului conținut către altul unique_ptr. A unique_ptrnu poate fi copiat deoarece constructorul său de copiere și operatorii de atribuire sunt șterse în mod explicit.
std::unique_ptr<int> p1(new int(5));
std::unique_ptr<int> p2 = p1; // Compile error.
std::unique_ptr<int> p3 = std::move(p1); // Transfers ownership. p3 now owns the memory and p1 is set to nullptr.
p3.reset(); // Deletes the memory.
p1.reset(); // Does nothing.
std::auto_ptreste depreciat sub C ++ 11 și complet eliminat din C ++ 17 . Constructorul de copiere și operatorii de alocare a auto_ptrcopierii nu pointerul stocat. În schimb, îl transferă , lăsând auto_ptrobiectul anterior gol. Aceasta a fost o modalitate de a implementa proprietatea strictă, astfel încât un singur auto_ptrobiect să poată deține indicatorul la un moment dat. Aceasta înseamnă că auto_ptrnu trebuie utilizat acolo unde este necesară semantica copierii. Întrucât auto_ptra existat deja cu semantica sa de copiere, acesta nu a putut fi actualizat pentru a fi un pointer numai mutare fără a rupe compatibilitatea cu codul existent.
C ++ 11 introduce std::shared_ptrși std::weak_ptr, definit în antet <memory>. C ++ 11 introduce, de asemenea, std::make_shared(a std::make_uniquefost introdus în C ++ 14) pentru a aloca în siguranță memoria dinamică în paradigma RAII .
A shared_ptreste un container pentru un indicator brut . Păstrează referința de numărare a dreptului de proprietate asupra indicatorului său conținut, în cooperare cu toate exemplarele shared_ptr. Un obiect la care se face referire prin indicatorul brut conținut va fi distrus când și numai când toate copiile acestuia shared_ptrau fost distruse.
std::shared_ptr<int> p0(new int(5)); // Valid, allocates 1 integer and initialize it with value 5.
std::shared_ptr<int[]> p1(new int[5]); // Valid, allocates 5 integers.
std::shared_ptr<int[]> p2 = p1; // Both now own the memory.
p1.reset(); // Memory still exists, due to p2.
p2.reset(); // Frees the memory, since no one else owns the memory.
A weak_ptreste un container pentru un indicator brut. Este creat ca o copie a unui shared_ptr. Existența sau distrugerea weak_ptrcopiilor shared_ptrnu au niciun efect asupra shared_ptrsau a celorlalte copii ale acesteia. După ce toate copiile unui shared_ptrau fost distruse, toate weak_ptrcopiile devin goale.
std::shared_ptr<int> p1 = std::make_shared<int>(5);
std::weak_ptr<int> wp1 {p1}; // p1 owns the memory.
{
std::shared_ptr<int> p2 = wp1.lock(); // Now p1 and p2 own the memory.
// p2 is initialized from a weak pointer, so you have to check if the
// memory still exists!
if (p2) {
DoSomethingWith(p2);
}
}
// p2 is destroyed. Memory is owned by p1.
p1.reset(); // Free the memory.
std::shared_ptr<int> p3 = wp1.lock();
// Memory is gone, so we get an empty shared_ptr.
if (p3) { // code will not execute
ActionThatNeedsALivePointer(p3);
}
Deoarece implementarea numărării referințelorshared_ptr utilizează , referințele circulare sunt potențial o problemă. Un lanț circular poate fi rupt prin schimbarea codului astfel încât una dintre referințe să fie a .
shared_ptrweak_ptr
Mai multe fire pot accesa în siguranță simultan diferite shared_ptrși weak_ptrobiecte care indică același obiect.
Obiectul menționat trebuie protejat separat pentru a asigura siguranța firului .
shared_ptrși weak_ptrse bazează pe versiunile utilizate de bibliotecile Boost . C ++ Technical Report 1 (TR1) le-a introdus mai întâi în standard, ca utilități generale , dar C ++ 11 adaugă mai multe funcții, în conformitate cu versiunea Boost.
Vezi si
- Numărare automată a referințelor
- Achiziționarea resurselor este inițializarea (RAII)
- auto_ptr
- Indicator opac
- Referință (informatică)
- Boost (biblioteci C ++)
- Indicator de grăsime
- Colectarea gunoiului în programarea computerelor
Referințe
Lecturi suplimentare
- Scott Meyers (2014). C ++ modern eficient . Sebastopol, CA: O'Reilly Media . ISBN 978-1491903995. OCLC 884480640 .
linkuri externe
- Indicatoare inteligente . Design modern C ++ : programare generică și modele de proiectare aplicate de Andrei Alexandrescu , Addison-Wesley, 2001.
- countptr.hpp . Biblioteca standard C ++ - Tutorial și referință de Nicolai M. Josuttis
- Sporiți indicatoarele inteligente
- Noul C ++: indicatoare inteligente (er) . Herb Sutter 1 august 2002
- Smart Pointers - Ce, De ce, Care? . Yonat Sharon
- Smart Pointers Prezentare generală . John M. Dlugosz
- Smart Pointers în Delphi
- Smart Pointers în rugină
- Smart Pointers în C ++ modern