Słyszałem, auto_ptr
że w C ++ 11 jest przestarzały. Jaki jest tego powód?
Chciałbym również poznać różnicę między auto_ptr
i shared_ptr
.
c++
c++11
smart-pointers
auto-ptr
brett
źródło
źródło
Odpowiedzi:
Bezpośrednim zamiennikiem
auto_ptr
(lub i tak najbliższym temu) jestunique_ptr
. Jeśli chodzi o „problem”, sprawa jest całkiem prosta:auto_ptr
przenosi własność, gdy jest przypisana.unique_ptr
przenosi również własność, ale dzięki kodyfikacji semantyki ruchu i magii odniesień do wartości r może to zrobić znacznie bardziej naturalnie. Znacznie lepiej „pasuje” do reszty biblioteki standardowej (choć, uczciwie mówiąc, część z nich jest spowodowana zmianą reszty biblioteki w celu dostosowania do semantyki przenoszenia, zamiast konieczności ciągłego kopiowania).Zmiana nazwy jest również (IMO) mile widziana -
auto_ptr
tak naprawdę niewiele mówi o tym, co próbuje zautomatyzować, aunique_ptr
jest dość rozsądnym (choć zwięzłym) opisem tego, co jest dostarczane.źródło
auto_ptr
nazwie: auto sugeruje automatyczne, jak w zmiennej automatycznej, i odnosi się do jednej rzeczy, któraauto_ptr
robi: zniszczenie zarządzanego zasobu w jego destruktorze (kiedy wyjdzie poza zakres).auto_ptr
: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…std::sort
nie ma specjalizacji dlaunique_ptr
. Zamiast tego określono ponownie, aby nigdy nie kopiować. Więcauto_ptr
faktycznie robi pracę z nowoczesnymsort
. Ale C ++ 98/03sort
to tylko przykładowy algorytm tutaj: Każdy algorytm ogólny (dostarczony standardowo lub napisany przez użytkownika), który zakłada, że składnia kopiowania ma semantykę kopiowania, prawdopodobnie będzie miał błąd czasu wykonania, jeśli zostanie użyty zauto_ptr
, ponieważauto_ptr
cicho porusza się ze składnią kopiowania . Problem jest znacznie większy niż tylkosort
.Uważam, że istniejące odpowiedzi są świetne, ale z punktu początkowego wskaźników. IMO, idealna odpowiedź powinna mieć odpowiedź z perspektywy użytkownika / programisty.
Po pierwsze (jak wskazał Jerry Coffin w swojej odpowiedzi)
shared_ptr: Jeśli obawiasz się zwolnienia zasobów / pamięci ORAZ jeśli masz więcej niż jedną funkcję, która może używać obiektu AT-RIFFERENT razy, przejdź do shared_ptr.
Przez DIFFERENT-Times wyobraź sobie sytuację, w której obiekt-ptr jest przechowywany w wielu strukturach danych i później dostępny. Oczywiście wiele wątków to kolejny przykład.
unique_ptr: Jeśli wszystko, co cię niepokoi, to zwolnienie pamięci, a dostęp do obiektu jest SEQUENTIAL, przejdź do unique_ptr.
Przez SEQUENTIAL mam na myśli, że w dowolnym momencie dostęp do obiektu będzie możliwy z jednego kontekstu. Np. Obiekt, który został utworzony i użyty natychmiast po utworzeniu przez twórcę. Po utworzeniu obiekt jest przechowywany w strukturze danych FIRST . Następnie obiekt jest niszczony po JEDNEJ strukturze danych lub przenoszony do DRUGIEJ struktury danych.
W tym wierszu będę odnosić się do shared / unique _ptr jako smart-pointers. (auto_ptr jest również smart-pointer, ALE z powodu błędów w jego projekcie, dla których są przestarzałe i które myślę, że wskażę w następnych wierszach, nie powinny być grupowane ze smart-pointer.)
Z linku: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/
Rodzaj zadań obsługiwanych przez unqiue_ptr
Od: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/
Rodzaj zadań obsługiwanych przez auto_ptr
Przechodząc teraz do powodu DLACZEGO samo przypisanie kopii było tak nielubiane, mam następującą teorię:
Niezamierzone zachowanie jest naprawdę nielubiane, stąd niechęć do auto_ptr.
(Dla 3.1415926536% programistów, którzy celowo chcą przenieść własność C ++ 11, dało im std :: move (), co jasno pokazało ich zamiar wszystkim stażystom, którzy będą czytać i utrzymywać kod.)
źródło
auto_ptr
wartości wskazywały na ten sam obiekt (ponieważ nie dają one współwłasności, pierwsza, która umrze, pozostawi drugą ze śmiercionośnym dziedzictwem; dotyczy to równieżunique_ptr
użycia), czy możesz zasugerować, co było zamierzone w pozostałe 96,8584073465% całego wykorzystania?*a=*b;
tutaj tylko wartość b jest kopiowana do a. Mam nadzieję, że zarówno a, jak i b są nadal własnością tych samych osób. Wspomniałeś, że własność zostanie przeniesiona. Jak to będzie?auto_ptr
samego obiektu. Przypisywanie do / z jej wskazanej wartości nie ma wpływu na własność ani nie ma dla niej znaczenia. Mam nadzieję, że nadal nie używaszauto_ptr
?shared_ptr
można przechowywać w pojemnikach.auto_ptr
żargon.BTW
unique_ptr
to naprawdę bezpośredniauto_ptr
zamiennik, łączy w sobie najlepsze cechy obustd::auto_ptr
iboost::scoped_ptr
.źródło
Jeszcze jedno podejście do wyjaśnienia różnicy ...
Funkcjonalnie, C ++ 11
std::unique_ptr
jest „ustalonym”std::auto_ptr
: oba są odpowiednie, gdy - w dowolnym momencie podczas wykonywania - powinien istnieć jeden właściciel inteligentnego wskaźnika dla wskazanego obiektu.Istotna różnica polega na tworzeniu kopii lub przypisywaniu z innego nie wygasającego inteligentnego wskaźnika, pokazanego w
=>
liniach poniżej:std::auto_ptr<T> ap(...); std::auto_ptr<T> ap2(get_ap_to_T()); // take expiring ownership => std::auto_ptr<T> ap3(ap); // take un-expiring ownership ala ap3(ap.release()); ap->xyz; // oops... can still try to use ap, expecting it to be non-NULL std::unique_ptr<T> up(...); std::unique_ptr<T> up2(get_up_to_T()); // take expiring ownership => std::unique_ptr<T> up3(up); // COMPILE ERROR: can't take un-expiring ownership => std::unique_ptr<T> up4(std::move(up)); // EXPLICIT code allowed => std::unique_ptr<T> up4(up.release()); // EXPLICIT code allowed
Powyżej,
ap3
po cichu „kradnie” własność*ap
, pozostawiającap
ustawienie anullptr
, a problem polega na tym, że może się to zdarzyć zbyt łatwo, bez przemyślenia przez programistę jego bezpieczeństwa.Na przykład, jeśli
class
/struct
mastd::auto_ptr
składową, utworzenie kopii instancji spowodujerelease
wyświetlenie wskaźnika z kopiowanej instancji: to dziwna i niebezpiecznie myląca semantyka, ponieważ zwykle kopiowanie czegoś jej nie modyfikuje. Autorowi klasy / struktury łatwo jest przeoczyć zwolnienie wskaźnika podczas wnioskowania o niezmiennikach i stanie, aw konsekwencji przypadkowo podjąć próbę wyłuskiwania inteligentnego wskaźnika, gdy ma wartość null, lub po prostu nie spodziewał się dostępu / własności wskazanych danych.źródło
Auto_ptr nie może być używany w kontenerach STL, ponieważ ma konstruktor kopiujący, który nie spełnia wymagań kontenera CopyConstructible . unique_ptr nie implementuje konstruktora kopiującego, więc kontenery używają alternatywnych metod. unique_ptr może być używany w kontenerach i jest szybszy dla algorytmów std niż shared_ptr.
#include <iostream> #include <type_traits> #include <vector> #include <memory> using namespace std; int main() { cout << boolalpha; cout << "is_copy_constructible:" << endl; cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl; cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl; cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl; vector<int> i_v; i_v.push_back(1); cout << "i_v=" << i_v[0] << endl; vector<int> i_v2=i_v; cout << "i_v2=" << i_v2[0] << endl; vector< unique_ptr<int> > u_v; u_v.push_back(unique_ptr<int>(new int(2))); cout << "u_v=" << *u_v[0] << endl; //vector< unique_ptr<int> > u_v2=u_v; //will not compile, need is_copy_constructible == true vector< unique_ptr<int> > u_v2 =std::move(u_v); // but can be moved cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl; vector< shared_ptr<int> > s_v; shared_ptr<int> s(new int(3)); s_v.push_back(s); cout << "s_v=" << *s_v[0] << endl; vector< shared_ptr<int> > s_v2=s_v; cout << "s_v2=" << *s_v2[0] << endl; vector< auto_ptr<int> > a_v; //USAGE ERROR return 0; } >cxx test1.cpp -o test1 test1.cpp: In function âint main()â: test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations] vector< auto_ptr<int> > a_v; //USAGE ERROR ^ >./test1 is_copy_constructible: auto_ptr: false unique_ptr: false shared_ptr: true i_v=1 i_v2=1 u_v=2 s_v=3 s_v2=3
źródło