Próbuję zrozumieć, jak std::unique_ptr
działa i do tego znalazłem ten dokument. Autor zaczyna od następującego przykładu:
#include <utility> //declarations of unique_ptr
using std::unique_ptr;
// default construction
unique_ptr<int> up; //creates an empty object
// initialize with an argument
unique_ptr<int> uptr (new int(3));
double *pd= new double;
unique_ptr<double> uptr2 (pd);
// overloaded * and ->
*uptr2 = 23.5;
unique_ptr<std::string> ups (new std::string("hello"));
int len=ups->size();
To, co jest dla mnie mylące, to ta kwestia
unique_ptr<int> uptr (new int(3));
Używamy liczby całkowitej jako argumentu (w okrągłych nawiasach) i tutaj
unique_ptr<double> uptr2 (pd);
użyliśmy wskaźnika jako argumentu. Czy to ma znaczenie?
Nie jest też dla mnie jasne, jak wskaźniki deklarowane w ten sposób będą się różniły od wskaźników deklarowanych w „normalny” sposób.
c++
pointers
std
unique-ptr
rzymski
źródło
źródło
new int(3)
zwraca wskaźnik do nowegoint
, tak jakpd
wskaźnik do nowegodouble
.Odpowiedzi:
Konstruktor klasy
unique_ptr<T>
przyjmuje surowy wskaźnik do obiektu typuT
(a więc akceptuje aT*
).W pierwszym przykładzie:
unique_ptr<int> uptr (new int(3));
Wskaźnik jest wynikiem
new
wyrażenia, podczas gdy w drugim przykładzie:unique_ptr<double> uptr2 (pd);
Wskaźnik jest przechowywany w
pd
zmiennej.Koncepcyjnie nic się nie zmienia (konstruujesz a
unique_ptr
z surowego wskaźnika), ale drugie podejście jest potencjalnie bardziej niebezpieczne, ponieważ pozwoliłoby ci na przykład:unique_ptr<double> uptr2 (pd); // ... unique_ptr<double> uptr3 (pd);
W ten sposób posiadanie dwóch unikalnych wskaźników, które skutecznie hermetyzują ten sam obiekt (naruszając w ten sposób semantykę unikalnego wskaźnika).
Dlatego pierwsza forma tworzenia unikalnego wskaźnika jest lepsza, jeśli to możliwe. Zauważ, że w C ++ 14 będziemy mogli:
unique_ptr<int> p = make_unique<int>(42);
Co jest zarówno jaśniejsze, jak i bezpieczniejsze. A jeśli chodzi o tę twoją wątpliwość:
Inteligentne wskaźniki mają modelować własność obiektu i automatycznie dbać o zniszczenie wskazanego obiektu, gdy ostatni (inteligentny, posiadający) wskaźnik do tego obiektu znajdzie się poza zakresem.
W ten sposób nie musisz pamiętać wykonywania czynności
delete
na obiektach alokowanych dynamicznie - destruktor inteligentnego wskaźnika zrobi to za Ciebie - ani martwić się, czy nie wyłuskujesz (wiszącego) wskaźnika do obiektu, który został już zniszczony:{ unique_ptr<int> p = make_unique<int>(42); // Going out of scope... } // I did not leak my integer here! The destructor of unique_ptr called delete
Now
unique_ptr
jest inteligentnym wskaźnikiem, który modeluje unikalną własność, co oznacza, że w dowolnym momencie w programie będzie tylko jeden wskaźnik (będący właścicielem) wskazanego obiektu - dlategounique_ptr
nie można go skopiować.Dopóki używasz inteligentnych wskaźników w sposób, który nie narusza niejawnej umowy, której wymagają od ciebie, będziesz mieć gwarancję, że żadna pamięć nie zostanie ujawniona, a odpowiednia polityka własności dla twojego obiektu będzie egzekwowana. Surowe wskazówki nie dają takiej gwarancji.
źródło
model object ownership
, tyminteger leak
w kodzie lubenforcing ownership policy for object
. Czy mógłbyś zasugerować tematy / zasoby, aby nauczyć się tych koncepcji?unique_ptr
, bez błędu:The text ">" is unexpected. It may be that this token was intended as a template argument list terminator but the name is not known to be a template.
mimo że mam#include <utility>
i#include <memory>
. Jakakolwiek rada?Nie ma różnicy w działaniu obu koncepcji przypisania do unique_ptr.
int* intPtr = new int(3); unique_ptr<int> uptr (intPtr);
jest podobne do
unique_ptr<int> uptr (new int(3));
Tutaj unique_ptr automatycznie usuwa przestrzeń zajmowaną przez
uptr
.Jeśli utworzysz liczbę całkowitą w przestrzeni sterty (używając słowa kluczowego new lub malloc ), będziesz musiał samodzielnie wyczyścić tę pamięć (używając odpowiednio delete lub free ).
W poniższym kodzie
int* heapInt = new int(5);//initialize int in heap memory . .//use heapInt . delete heapInt;
Tutaj będziesz musiał usunąć heapInt, gdy zostanie to wykonane za pomocą. Jeśli nie zostanie usunięty, nastąpi przeciek pamięci.
Aby uniknąć takich wycieków pamięci, używany jest unique_ptr , gdzie unique_ptr automatycznie usuwa miejsce zajmowane przez heapInt, gdy wychodzi poza zakres. Nie musisz więc usuwać ani bezpłatnie usuwać unique_ptr.
źródło
Unikalne wskaźniki gwarantują, że zniszczą obiekt, którym zarządzają, gdy wyjdą poza zasięg. http://en.cppreference.com/w/cpp/memory/unique_ptr
W tym przypadku:
unique_ptr<double> uptr2 (pd);
pd
zostanie zniszczony, gdyuptr2
wyjdzie poza zakres. Ułatwia to zarządzanie pamięcią poprzez automatyczne usuwanie.Przypadek
unique_ptr<int> uptr (new int(3));
nie jest inny, z wyjątkiem tego, że surowy wskaźnik nie jest tutaj przypisany do żadnej zmiennej.źródło
Z cppreference jednym z
std::unique_ptr
konstruktorów jestjawne unique_ptr (wskaźnik p) noexcept;
Tak więc, aby utworzyć nowy,
std::unique_ptr
należy przekazać wskaźnik do jego konstruktora.unique_ptr<int> uptr (new int(3));
Albo to jest to samo co
int *int_ptr = new int(3); std::unique_ptr<int> uptr (int_ptr);
Inna jest to, że po użyciu nie musisz sprzątać. Jeśli nie używasz
std::unique_ptr
(inteligentnego wskaźnika), będziesz musiał go usunąć w ten sposóbdelete int_ptr;
kiedy już go nie potrzebujesz lub spowoduje to wyciek pamięci.
źródło