auto_ptr
C ++ 11'de kullanımdan kaldırıldığını duydum . Bunun sebebi nedir?
Ayrıca auto_ptr
ve arasındaki farkı bilmek istiyorum shared_ptr
.
Yanıtlar:
Bunun doğrudan ikamesi auto_ptr
(ya da birine en yakın olanı) unique_ptr
. "Sorun" a gelince, oldukça basit: auto_ptr
atandığında sahipliği devrediyor. unique_ptr
ayrıca sahipliği de aktarır, ancak hareket anlambiliminin kodlanması ve rvalue referanslarının büyüsü sayesinde, bunu çok daha doğal bir şekilde yapabilir. Ayrıca, standart kitaplığın geri kalanıyla önemli ölçüde daha iyi "uyuyor" (yine de, bunun bir kısmı kitaplığın geri kalanının her zaman kopyalama gerektirmek yerine hareket semantiğini barındıracak şekilde değişmesi sayesinde).
İsim değişikliği de (IMO) hoş karşılanan bir özelliktir - auto_ptr
size neyi otomatikleştirmeye çalıştığı hakkında pek bir şey söylemezken, unique_ptr
sağlananlar hakkında oldukça makul (kısa ise) bir açıklama.
auto_ptr
İsme bir not : auto, otomatik değişkendeki gibi otomatik önerir ve bunu yapan tek bir şeye atıfta bulunur auto_ptr
: yönetilen kaynağı yok edicisinde (kapsam dışına çıktığında) yok edin.
auto_ptr
: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
std::sort
için bir uzmanlığı yok unique_ptr
. Bunun yerine asla kopyalanmaması için yeniden belirlendi. Yani auto_ptr
aslında yapar modern çalışmalarını sort
. Ancak C ++ 98/03 sort
, burada sadece bir örnek algoritmadır: Kopya sözdiziminin kopya semantiğine sahip olduğunu varsayan herhangi bir genel algoritma (std tarafından sağlanan veya kullanıcı tarafından yazılan), birlikte kullanıldığında büyük olasılıkla bir çalışma zamanı hatası verecektir auto_ptr
, çünkü auto_ptr
sessizce hareket eder ile kopya sözdizimi. Sorun sadece olandan çok daha büyük sort
.
Mevcut cevapları harika buldum, ancak işaretçilerin PoV'undan. IMO, ideal bir cevap, kullanıcı / programcının bakış açısına sahip olmalıdır.
İlk önce ilk şey (cevabında Jerry Coffin'in işaret ettiği gibi)
shared_ptr: Kaynağın / belleğin serbest bırakılmasıyla ilgileniyorsanız VE nesneyi AT-FARKLI zamanlarda kullanabilecek birden fazla işleviniz varsa, o zaman shared_ptr ile gidin.
DIFFERENT-Times'a göre, nesne-ptr'nin çoklu veri yapısında depolandığı ve daha sonra erişildiği bir durumu düşünün. Elbette birden fazla iş parçacığı başka bir örnek.
unique_ptr: Eğer tek ilgilendiğiniz bellek boşaltmaksa ve nesneye erişim SIRALI ise, o zaman unique_ptr için gidin.
SEQUENTIAL ile demek istediğim, herhangi bir noktada nesneye tek bir bağlamdan erişilecektir. Örneğin, yaratan tarafından yaratılan ve yaratıldıktan hemen sonra kullanılan bir nesne. Oluşturulduktan sonra, nesne İLK veri yapısında saklanır . Sonra ya nesne BİR veri yapısından sonra yok edilir ya da İKİNCİ veri yapısına taşınır .
Bu satırdan, paylaşılan / benzersiz _ptr'yi akıllı işaretçiler olarak adlandıracağım. (auto_ptr aynı zamanda akıllı işaretleyicidir AMA, tasarımındaki kusurlar nedeniyle, kullanımdan kaldırıldıkları ve sonraki satırlarda belirteceğimi düşündüğüm, akıllı işaretçi ile gruplandırılmamaları gerekir.)
Auto_ptr'nin neden akıllı işaretçi lehine kullanımdan kaldırıldığının tek ve en önemli nedeni, atama-anlambilimidir . Bu nedenle olmasaydı, auto_ptr'ye taşıma semantiğinin tüm yeni güzelliklerini kullanımdan kaldırmak yerine ekleyebilirlerdi. Atama-anlambilim en sevilmeyen özellik olduğu için, bu özelliğin ortadan kalkmasını istediler, ancak bu semantiği kullanan (standartlar komitesinin değiştiremeyeceği) bir kod yazıldığından, auto_ptr'yi bırakmak zorunda kaldılar. onu değiştirmek.
Bağlantıdan: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/
Unqiue_ptr tarafından desteklenen atama türleri
Gönderen: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/
Auto_ptr tarafından desteklenen atama türleri
Şimdi, kopya ödevinin kendisinin neden bu kadar sevilmediğine gelince, şu teoriye sahibim:
İstenmeyen davranış gerçekten beğenilmez ve bu nedenle auto_ptr için beğenilmez.
(C ++ 11'in mülkiyetini kasıtlı olarak devretmek isteyen programcıların% 3,1415926536'sı onlara std :: move () verdi, bu da kodu okuyacak ve koruyacak tüm stajyerler için niyetlerini çok net hale getirdi.)
auto_ptr
aynı nesneye işaret değerleri (bunlar ortak sahipliği vermek vermediği için, kalıba ilk ölümcül bir geçmişe sahip diğer bırakacaktır; bu da için de geçerlidir unique_ptr
kullanım), Önerebileceğin ne de amaçlanan tüm kullanımların% 96.8584073465'i kalan?
*a=*b;
burada sadece b'nin değeri a'ya kopyalanır. Umarım hem a hem de b'nin mülkiyeti hala aynı kişilere aittir. Owenership transfer edilecek gibi söylediniz. Nasıl olacak?
auto_ptr
nesnenin kendisine atamaktan bahsediyordu . Onun işaret edilen değere / değerinden devretmenin sahiplik üzerinde hiçbir etkisi veya ilgisi yoktur. Umarım hala kullanmıyorsundur auto_ptr
?
Yine farkı açıklayan başka bir yaklaşım ...
İşlevsel olarak, C ++ 11'ler std::unique_ptr
"sabittir" std::auto_ptr
: her ikisi de - yürütme sırasında herhangi bir zamanda - işaret edilen bir nesne için tek bir akıllı işaretçi sahibi olması gerektiğinde uygundur.
Önemli fark, =>
aşağıdaki satırlarda gösterilen, süresi dolmayan başka bir akıllı işaretçiden kopya oluşturma veya atamadır :
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
Yukarıda, ap3
sahipliğini sessizce "çalar" *ap
, ap
ayarı a olarak bırakır nullptr
ve sorun şu ki, programcı güvenliğini düşünmeden çok kolay olabilir.
Örneğin, bir class
/ üyesine struct
sahipse std::auto_ptr
, o zaman bir örneğin kopyasını yapmak kopyalanan örnekteki release
gösterici olacaktır : bu garip ve tehlikeli bir şekilde kafa karıştırıcı anlambilimdir, çünkü genellikle bir şeyi kopyalamak onu değiştirmez. Sınıf / yapı yazarının değişmezler ve durum hakkında akıl yürütürken göstericinin serbest bırakılmasını göz ardı etmesi ve sonuç olarak yanlışlıkla boş iken akıllı işaretçiyi kaldırmaya teşebbüs etmesi veya işaret edilen veriye erişme / sahiplik beklememesi kolaydır.
auto_ptr, konteyner CopyConstructible gereksinimlerini karşılamayan bir kopya oluşturucusuna sahip olduğu için STL konteynerlerinde kullanılamaz . unique_ptr bir kopya yapıcısı uygulamaz, bu nedenle kapsayıcılar alternatif yöntemler kullanır. unique_ptr kapsayıcılarda kullanılabilir ve standart algoritmalar için shared_ptr'den daha hızlıdır.
#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