Standart kaplarda std :: auto_ptr <> kullanmak neden yanlış?


217

std::auto_ptr<>Standart kaplarla kullanmak neden yanlıştır ?


5
Kesinlikle bir +1 çünkü bu kadar çok insanın bunu yanlış anladığını gördüm. Sormak harika bir soru.
twokats

Lütfen ilgili öğeyi de okuyun. Bu soru diğer taraftan burada ele alınmıştır. Auto_ptr ve STL kapsayıcıları hakkında daha fazla bilgi edinmek yardımcı olabilir. stackoverflow.com/questions/8630552/…
nickolay


1
moveanlambilimsel ve unique_ptrilgili sorunlardan kaçınmak için tasarlanmıştır auto_ptr. C ++ 03'te dil, auto_ptrderleyici ve dil l ve r değerlerini ayırt edemediğinden, istenen davranışları elde etmek için bazı "hackler" kullanıldığı için tüm senaryolarda doğru ve güvenli davranan böyle bir sınıf yazmak için yeterince güçlü değildi. çoğu zaman.
Phil1970

Güzel makale: STL Konteynerleri ve Auto_ptrs - Neden Karıştırmıyorlar quantstart.com/articles/…
alfC

Yanıtlar:


124

C ++ Standardı, bir STL öğesinin "kopyalanabilir" ve "atanabilir" olması gerektiğini belirtir. Başka bir deyişle, bir eleman atanabilmeli veya kopyalanabilmelidir ve iki eleman mantıksal olarak bağımsız olmalıdır. std::auto_ptrbu şartı yerine getirmez.

Örneğin bu kodu ele alalım:

class X
{
};

std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);

std::auto_ptr<X> pX = vecX[0];  // vecX[0] is assigned NULL.

Bu sınırlamanın üstesinden gelmek için std::unique_ptr, C ++ 11'iniz yoksa , std::shared_ptrveya std::weak_ptrakıllı işaretçileri veya yükseltme eşdeğerlerini kullanmalısınız. İşte bu akıllı işaretçiler için destek kitaplığı belgeleri.


7
Paylaşılan sahipliğe ihtiyacınız yoksa, yükseltme işaretçisi kapsayıcılarını da dikkate almalısınız.
me22 10:09

4
unique_ptrayrıca kopyalamaya da izin vermez, bu nedenle bazı STL işlemleri taşıma semantiğini kullanmadıkları sürece düzgün çalışmaz.
Mike Weller

4
"Bu sınırlamanın üstesinden gelmek için std::unique_ptr" kullanmalısınız ": bu sınıf şablonu yalnızca taşıma semantiği nedeniyle (belirtimi değer referansları gerektirir) kullanılabilir, bu nedenle temel olarak C ++ 11 gerektirir. Ancak (ve ilgili) C ++ 11 Standardı artık bir STL öğesi türünün "kopyalanabilir" ve "atanabilir" olması gerektiğini söylememektedir; harekete geçirilebilir ve taşımaya ayrılabilir yeterlilikler. Aslında unique_ptrörnekler yalnızca hareket ettirilebilir ve hareket ettirilebilirdir. Ama auto_ptrörnekler de öyle ! Sonuç olarak, C ++ 11 ile auto_ptryapabileceklerinizle yapabilirsiniz unique_ptr.
Marc van Leeuwen

@MarcvanLeeuwen sürece sen resetve releasegerektiği gibi
cırcır ucube

2
@ratchetfreak: Hmm, anlamıyorum. Ne? "Siz resetve " sürece release, bunun yorumumdaki herhangi bir şey için nasıl geçerli olduğunu göremiyorum. Her ikisinin de bu yöntemlere sahip olduğunu auto_ptrve unique_ptrher iki durumda da aynı şeyi yaptığını unutmayın.
Marc van Leeuwen

66

Kopya semantik ait auto_ptrkapların ile uyumlu değildir.

Özellikle, birini auto_ptrdiğerine kopyalamak , işaretleyicinin sahipliğini kaybettiği için iki eşit nesne oluşturmaz.

Daha spesifik olarak, kopyalanması, kopyalardan auto_ptrbirinin işaretçiyi bırakmasına neden olur. Bu kalıntıların hangisi kapta tanımlanmamıştır. Bu nedenle, auto_ptrskaplarda saklarsanız, işaretçilerin erişimini rastgele kaybedebilirsiniz .


39

Konuyla ilgili iki süper mükemmel makale:


Çünkü aradan geçen yaklaşık iki yıl içinde, muhtemelen eldeki problemle uğraştığını düşünüyorum.
Köpek yavrusu

27
@DeadMG: evet, haklısın. Ama bu benim amacım değildi. Birisi bu konuya bazen gelir ve hakkında bilgi edinmek istiyorsa auto_ptr, bu bağlantılar yardımcı olacaktır, eminim.
Lazer

Daha yeni olan birçok kopya var.
Köpek yavrusu

8
@DeadMG: Bu soru yinelenen olarak kapatılmadı ve bu nedenle uzantıya açık. Lazer burada daha önce söylenmeyenleri söyledi. Sanırım şans eseri geldi.
Sebastian Mach

Aradıktan sonra sorunu analiz eden ikinci bağlantıdaki açıklamalar, buradaki sort()tüm cevaplardan daha açıktır.
kaosink

17

STL kapları, içinde sakladığınız öğeleri kopyalayabilmeli ve orijinalin ve kopyanın eşdeğer olmasını bekleyecek şekilde tasarlanmıştır. otomatik işaretçi nesnelerinin tamamen farklı bir sözleşmesi vardır, böylece kopyalama bir sahiplik aktarımı oluşturur. Bu, auto_ptr kapsayıcılarının kullanıma bağlı olarak garip davranışlar göstereceği anlamına gelir.

Etkili STL (Scott Meyers) madde 8'de neyin yanlış gidebileceğinin ayrıntılı bir açıklaması ve ayrıca Etkili C ++ (Scott Meyers) madde 13'te çok ayrıntılı olmayan bir açıklama var.


12

STL kapları içerdiği öğelerin kopyalarını saklar. Bir auto_ptr kopyalandığında, eski ptr değerini null değerine ayarlar. Birçok kapsayıcı yöntemi bu davranış tarafından kırık.


Ancak, unique_ptr kullanırken yalnızca bir unique_ptr nesnenin sahibi olabileceğinden hemen hemen aynı şeyi alırsınız?
Tracer

2
@Tracer unique_ptrherhangi bir uygun C ++ 11 nesne, sadece hareket-inşa edilmiş ya da -görevlendiren zaman programcı kasıtlı olarak geçmesi gereken sağlanması, kaynak sahipliğini aktarabilir gibi std::move(sourceObject)yerine bir geçme yerine, veya geçici lvalue beklenmedik bu mutasyona uğratılmış olan / unintuitively ve burada tam olarak vurgulandığı gibi, temel bir sorun olan kopya ataması auto_ptr.
underscore_d

4

C ++ 03 Standardı (ISO-IEC 14882-2003) , 20.4.5 paragraf 3'teki fıkra uyarınca:

[...] [ Not: [...] auto_ptr, Standart Kitaplık kapsayıcısı öğeleri için CopyConstructible ve Atanabilir gereksinimlerini karşılamaz ve bu nedenle otomatik_ptr ile bir Standart Kitaplık kapsayıcısının başlatılması tanımlanmamış davranışla sonuçlanır. - son not ]

C ++ 11 Standardı (ISO-IEC 14882-2011) ek D.10.1 paragraf 3'te şunları söylüyor:

[...] Not: [...] auto_ptr örnekleri MoveConstructible ve MoveAssignable gereksinimlerini karşılar, ancak CopyConstructible ve CopyAssignable gereksinimlerini karşılamaz. - son not]

C ++ 14 Standardı (ISO-IEC 14882-2014) Ek C.4.2 Ek D'de belirtilen uyumluluk özellikleri:

Değiştir : auto_ptr, unary_function ve binary_function sınıf şablonları, random_shuffle işlev şablonları ve ptr_fun, mem_fun, mem_fun_ref, bind1st ve bind2nd işlev şablonları tanımlanmamıştır.
Gerekçe : Yeni özelliklerin yerini almıştır.
Orijinal özellik üzerindeki etki : Bu sınıf şablonlarını ve işlev şablonlarını kullanan geçerli C ++ 2014 kodu, bu Uluslararası Standartta derlenemeyebilir.

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.