Yanıtlar:
Her akıllı işaretçiyi atayabileceğiniz özelliklere sahip olduğunuzda kolaydır. Üç önemli özellik vardır.
Birincisi, akıllı bir işaretçinin nesneye sahip olmadığı için nesneyi silemeyeceği anlamına gelir. İkincisi, aynı anda yalnızca bir akıllı işaretçinin aynı nesneyi gösterebileceği anlamına gelir. Akıllı işaretçi işlevlerden döndürülecekse, örneğin sahiplik iade edilen akıllı işaretleyiciye aktarılır.
Üçüncüsü, çoklu akıllı işaretçilerin aynı nesneyi aynı anda gösterebileceği anlamına gelir. Bu uygulanır ham pointer ancak ham işaretçileri önemli özellik olmadığından, çok: Onlar ister tanımlamaz sahibi ya da değil. Her sahip nesneyi bıraktığında, sahiplik akıllı işaretçisinin paylaşımı nesneyi siler. Bu davranışa sık sık ihtiyaç duyulur, bu nedenle akıllı işaretçilerin sahibi olmak yaygın olarak yayılır.
Bazı akıllı işaretçiler ne ikincisini ne de üçüncüsünü desteklemez. Bu nedenle işlevlerden döndürülemez veya başka bir yere geçirilemezler. Hangisi için en uygunRAII
Akıllı işaretçinin yerel tutulduğu amaçlar ve sadece bir nesneyi kapsam dışına çıktıktan sonra serbest bırakır.
Mülkiyet payı bir kopya kurucuya sahip olarak uygulanabilir. Bu, doğal olarak akıllı bir işaretçiyi kopyalar ve hem kopya hem de orijinal aynı nesneyi referans alır. Sahiplik aktarımı şu anda C ++ 'da gerçekten uygulanamıyor çünkü bir şeyi dil tarafından desteklenen bir nesneden diğerine aktarmanın bir yolu yok: Bir nesneyi bir işlevden döndürmeye çalışırsanız, olan şey nesnenin kopyalanmasıdır. Dolayısıyla, sahiplik aktarımını uygulayan akıllı bir işaretçi, sahiplik aktarımını uygulamak için kopya yapıcısını kullanmalıdır. Bununla birlikte, bu da kaplarda kullanımını bozar, çünkü gereksinimler kapların elemanlarının kopya yapıcısının bu akıllı işaretçilerin bu "hareketli kurucu" davranışı ile uyumlu olmayan belirli bir davranışını belirtir.
C ++ 1x, "move yapıcıları" ve "move atama işleçleri" tanıtarak sahiplik aktarımı için yerel destek sağlar. Ayrıca böyle bir mülkiyet devri akıllı işaretçisi ile birlikte gelir unique_ptr
.
scoped_ptr
ne aktarılabilir ne de paylaşılabilir akıllı bir göstergedir. Yerel olarak bellek ayırmanız gerekiyorsa kullanılabilir, ancak kapsam dışı olduğunda tekrar serbest bırakıldığından emin olun. Ama yine de, isterseniz başka bir scoped_ptr ile değiştirilebilir.
shared_ptr
sahipliğini paylaşan akıllı bir işaretçi (yukarıdaki üçüncü tür). Referans sayılır, böylece son kopyasının kapsam dışına çıktığında ve yönetilen nesneyi serbest bıraktığında görebilir.
weak_ptr
sahibi olmayan bir akıllı işaretçi. Referans sayısı eklemeden yönetilen bir nesneye (paylaşılan_ptr tarafından yönetilen) referans vermek için kullanılır. Normalde, ham işaretçiyi shared_ptr öğesinden çıkarmanız ve kopyalamanız gerekir. Ancak nesnenin gerçekten ne zaman silindiğini kontrol etmenin bir yolu olmadığından bu güvenli olmaz. Bu nedenle, zayıf_ptr, paylaşılan_ptr tarafından yönetilen bir nesneye başvurarak araç sağlar. Nesneye erişmeniz gerekiyorsa, nesnenin yönetimini kilitleyebilirsiniz (başka bir iş parçacığında, nesneyi kullanırken bir shared_ptr öğesinin onu serbest bırakmasını önlemek için) ve ardından onu kullanabilirsiniz. Poor_ptr zaten silinmiş bir nesneyi gösteriyorsa, bir istisna atarak sizi fark edecektir. Döngüsel bir referansınız olduğunda poor_ptr kullanmak en yararlısıdır: Referans sayımı böyle bir durumla kolayca baş edemez.
intrusive_ptr
bir paylaşılan_ptr gibidir ancak referans sayısını paylaşılan_ptr içinde tutmaz, ancak sayımı yönetilen nesne tarafından tanımlanması gereken bazı yardımcı işlevlere arttırır / azaltır. Bunun avantajı, daha önce referans alınan bir nesnenin (harici bir referans sayma mekanizması tarafından artırılan bir referans sayısı olan) bir intrusive_ptr içine doldurulabilmesidir - çünkü referans sayısı artık akıllı işaretçinin içinde değildir, ancak akıllı işaretçi mevcut bir referans sayma mekanizması.
unique_ptr
sahiplik göstergesinin aktarılmasıdır. Kopyalayamazsınız, ancak C ++ 1x'in hareket yapıcılarını kullanarak taşıyabilirsiniz:
unique_ptr<type> p(new type);
unique_ptr<type> q(p); // not legal!
unique_ptr<type> r(move(p)); // legal. p is now empty, but r owns the object
unique_ptr<type> s(function_returning_a_unique_ptr()); // legal!
Bu, std :: auto_ptr'in uyduğu semantiktir, ancak taşınması için yerel desteğin eksik olması nedeniyle, onlara tuzaklar olmadan sağlayamaz. unique_ptr, taşıma semantiğinin temel özelliklerinden biri olan geçici bir unique_ptr kaynağından otomatik olarak kaynakları çalacaktır. auto_ptr, sonraki C ++ Standard sürümünde unique_ptr lehine kullanımdan kaldırılacaktır. C ++ 1x, yalnızca hareket edebilen ancak kaplara kopyalanamayan nesnelerin doldurulmasına da izin verir. Böylece unique_ptr'leri bir vektöre aktarabilirsiniz. Burada duracağım ve bunun hakkında daha fazla okumak isterseniz sizi bu konuyla ilgili güzel bir makaleye yönlendireceğim .
auto_ptr
zaten kullanımdan kaldırıldı (C ++ 11).
intrusive_ptr
tercih edilebileceği de söylendi shared_ptr
. Görünüşe göre, referans sayısını ayrı bir nesne yerine yönetilen nesnenin kendisinin belleğinin bir parçası olarak saklarsanız daha iyi performans gösterir. Bu, yönetilen nesnenin bir şablonunda veya üst sınıfında uygulanabilir.
scoped_ptr en basitidir. Kapsam dışına çıktığında yok edilir. Aşağıdaki kod geçersizdir (scoped_ptrs kopyalanamaz) ancak bir noktayı gösterir:
std::vector< scoped_ptr<T> > tPtrVec;
{
scoped_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// raw T* is freed
}
tPtrVec[0]->DoSomething(); // accessing freed memory
shared_ptr referans sayılır. Her kopya veya atama gerçekleştiğinde, referans sayımı artırılır. Bir örneğin yıkıcısı her tetiklendiğinde, ham T * için referans sayısı azaltılır. 0 olduğunda, işaretçi serbest bırakılır.
std::vector< shared_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
// This copy to tPtrVec.push_back and ultimately to the vector storage
// causes the reference count to go from 1->2
tPtrVec.push_back(tPtr);
// num references to T goes from 2->1 on the destruction of tPtr
}
tPtrVec[0]->DoSomething(); // raw T* still exists, so this is safe
poor_ptr , shared_ptr'e yönlendirilen işaretin hala etrafta olup olmadığını kontrol etmenizi gerektiren paylaşılan bir işaretçiye zayıf başvuru
std::vector< weak_ptr<T> > tPtrVec;
{
shared_ptr<T> tPtr(new T());
tPtrVec.push_back(tPtr);
// num references to T goes from 1->0
}
shared_ptr<T> tPtrAccessed = tPtrVec[0].lock();
if (tPtrAccessed[0].get() == 0)
{
cout << "Raw T* was freed, can't access it"
}
else
{
tPtrVec[0]->DoSomething(); // raw
}
intrusive_ptr genellikle kullanmanız gereken bir 3. taraf akıllı ptr olduğunda kullanılır. Referans sayısını eklemek ve azaltmak için ücretsiz bir işlev çağırır.Daha fazla bilgi için belgeleri artırma bağlantısına bakın .
if (tPtrAccessed[0].get() == 0)
varsayalım if (tPtrAccessed.get() == 0)
?
boost::ptr_container
Herhangi bir boost akıllı işaretçi araştırmasında göz ardı etmeyin . Örneğin std::vector<boost::shared_ptr<T> >
, çok yavaş olacağı durumlarda çok değerli olabilirler .
İkinci olarak belgelere bakmayla ilgili tavsiyem. Göründüğü kadar korkutucu değil. Ve birkaç kısa ipucu:
scoped_ptr
- kapsam dışına çıktığında bir işaretçi otomatik olarak silinir. Not - atama yapılamaz, ancak ek yük getirmezintrusive_ptr
- ek yükü olmayan referans sayma işaretçisi smart_ptr
. Ancak nesnenin kendisi referans sayısını saklarweak_ptr
- shared_ptr
Dairesel bağımlılıklarla sonuçlanan durumlarla başa çıkmak için birlikte çalışır (belgeleri okuyun ve Google'da güzel resim arayın;)shared_ptr
- akıllı göstergelerin genel, en güçlü (ve ağır ağırlığı) (boost tarafından sunulanlardan)auto_ptr
kontrol bir kapsamdan çıktığında işaret ettiği nesnenin otomatik olarak yok edilmesini sağlayan eski vardır . Ancak diğerlerinden farklı kopya semantiği vardır.unique_ptr
- C ++ 0x ile gelecekDüzenleme yanıtı: Evet