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
.
Odpowiedzi:
Bezpośrednim zamiennikiem auto_ptr
(lub i tak najbliższym temu) jest unique_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ć, a unique_ptr
jest dość rozsądnym (choć zwięzłym) opisem tego, co jest dostarczane.
auto_ptr
nazwie: auto sugeruje automatyczne, jak w zmiennej automatycznej, i odnosi się do jednej rzeczy, która auto_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 dla unique_ptr
. Zamiast tego określono ponownie, aby nigdy nie kopiować. Więc auto_ptr
faktycznie robi pracę z nowoczesnym sort
. Ale C ++ 98/03 sort
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 z auto_ptr
, ponieważ auto_ptr
cicho porusza się ze składnią kopiowania . Problem jest znacznie większy niż tylko sort
.
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.)
Jednym z najważniejszych powodów, dla których auto_ptr zostało uznane za przestarzałe na korzyść smart-pointer, jest semantyka przypisania. Gdyby nie z tego powodu, dodaliby wszystkie nowe zalety semantyki przenoszenia do auto_ptr zamiast go wycofywać. Ponieważ semantyka przypisania była najbardziej nielubiana, chcieli, aby ta funkcja zniknęła, ale ponieważ istnieje kod, który używa tej semantyki (której komisja normalizacyjna nie może zmienić), musieli puścić auto_ptr, zamiast modyfikowanie go.
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.)
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żywasz auto_ptr
?
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ąc ap
ustawienie a nullptr
, 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
ma std::auto_ptr
składową, utworzenie kopii instancji spowoduje release
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.
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