Auto_ptr neden kullanımdan kaldırılıyor?


Yanıtlar:


93

Bunun doğrudan ikamesi auto_ptr(ya da birine en yakın olanı) unique_ptr. "Sorun" a gelince, oldukça basit: auto_ptratandığında sahipliği devrediyor. unique_ptrayrı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_ptrsize neyi otomatikleştirmeye çalıştığı hakkında pek bir şey söylemezken, unique_ptrsağlananlar hakkında oldukça makul (kısa ise) bir açıklama.


25
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.
Vincenzo Pii

14
Daha fazla bilgi: Kullanımdan kaldırmanın resmi mantığı auto_ptr: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
Howard Hinnant

@HowardHinnant ilginç doc! std :: sort () 'nin std :: unique_ptr için gerektiği gibi hareket anlamsalını kullanmak için bir uzmanlığı olması bir anlamda gariptir. Belgede belirtilen kopyalama sorununu düzeltmek için std :: sort () neden std :: auto_ptr için özelleştirilemiyor merak ediyorum. Şimdiden teşekkürler.
Hei

2
@Hei: std::sortiçin bir uzmanlığı yok unique_ptr. Bunun yerine asla kopyalanmaması için yeniden belirlendi. Yani auto_ptraslı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_ptrsessizce hareket eder ile kopya sözdizimi. Sorun sadece olandan çok daha büyük sort.
Howard Hinnant

36

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)

  • auto_ptr duruma bağlı olarak shared_ptr veya unique_ptr ile değiştirilebilir

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

  • taşıma ataması (1)
  • boş işaretçi ata (2)
  • tip atama (3)
  • ödevi kopyala (silindi!) (4)

Gönderen: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

Auto_ptr tarafından desteklenen atama türleri

  • ödevi kopyala (4) suçlu

Şimdi, kopya ödevinin kendisinin neden bu kadar sevilmediğine gelince, şu teoriye sahibim:

  1. Tüm programcılar kitap veya standart okumaz
  2. karşısındaki auto_ptr, size nesnenin sahipliğini vaat ediyor
  3. auto_ptr'nin tüm programcılar tarafından okunmayan küçük- * (punto amaçlanan) cümlesi, bir auto_ptr'nin diğerine atanmasına izin verir ve sahipliği devreder.
  4. Araştırmalar, bu davranışın tüm kullanımların% 3,1415926535'i için tasarlandığını ve diğer durumlarda istenmeyen olduğunu göstermiştir.

İ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.)


1
Eğer bu yana asla iki istediğiniz auto_ptraynı 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_ptrkullanım), Önerebileceğin ne de amaçlanan tüm kullanımların% 96.8584073465'i kalan?
Marc van Leeuwen

Hepsi adına konuşamıyorum, ama tahmin ediyorum , nesne sahipliğinin taşındığını ve sadece çoğaltılmadığını, bu da hatalı olduğunu düşünürler .
Ajeet Ganga

@AjeetGanga Aşağıdaki 'küçük- * (punto amaçlanmıştır)' ifadesinde, "amaçlanan" olarak bahsetmiştin. Bu cümle benim için yeni ve her nasılsa Google'da araştırdım ve burada kasıtlı olarak yapılmış bir şaka olduğunu anladım. Buradaki şaka ne? Bunu bilmek merak ediyorum.
VINOTH ENERGETIC

@AjeetGanga 'Küçük- * (punto amaçlanan), auto_ptr'nin tüm programcılar tarafından okunmayan fıkrası, izin verir, bir auto_ptr'nin diğerine atanmasını sağlar ve sahipliği devreder'. Diyelim ki tamsayıya a ve b olarak iki otomatik ptr var. Atamayı yapıyorum, *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?
VINOTH ENERGETIC

@VINOTHENERGETIC Ajeet, bir auto_ptrnesnenin 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?
underscore_d

23

shared_ptrkaplarda saklanabilir. auto_ptryapamam.

BTW unique_ptrgerçekten doğrudan auto_ptrikame, hem std::auto_ptrve hem de en iyi özelliklerini birleştiriyor boost::scoped_ptr.


11

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, ap3sahipliğini sessizce "çalar" *ap, apayarı a olarak bırakır nullptrve sorun şu ki, programcı güvenliğini düşünmeden çok kolay olabilir.

Örneğin, bir class/ üyesine structsahipse std::auto_ptr, o zaman bir örneğin kopyasını yapmak kopyalanan örnekteki releasegö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 sahipliği sessizce "çalıyor" +1
camino

3

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.