Hangi akıllı işaretçiyi kullanacağınıza karar vermek bir sahiplenme meselesidir . Kaynak yönetimi söz konusu olduğunda, A nesnesinin sahibi nesnesinin B ömrünün kontrolünde olması durumunda nesnesinin B olur. Örneğin, üye değişkenlerin ömrü nesnenin ömrüne bağlı olduğu için üye değişkenler kendi nesnelerine aittir. Nesnenin sahiplenme biçimine göre akıllı işaretçiler seçersiniz.
Bir yazılım sistemindeki sahipliğin, yazılım dışında düşündüğümüz gibi sahiplikten ayrı olduğunu unutmayın. Örneğin, bir kişi evine "sahip olabilir", ancak bu mutlaka bir Person
nesnenin bir nesnenin ömrü boyunca kontrol sahibi olduğu anlamına gelmez House
. Bu gerçek dünya kavramlarını yazılım kavramlarıyla karıştırmak, kendinizi bir deliğe programlamanın kesin bir yoludur.
Nesnenin tek sahipliğiniz varsa kullanın std::unique_ptr<T>
.
Nesnenin sahipliğini paylaştıysanız ...
- Sahiplikte herhangi bir döngü yoksa kullanın std::shared_ptr<T>
.
- Çevrimler varsa, bir "yön" tanımlayın ve std::shared_ptr<T>
bir yönde kullanın vestd::weak_ptr<T>
diğer .
Nesne size aitse, ancak sahip sahibi olma potansiyeli yoksa normal işaretçiler kullanın T*
(örn. Üst işaretçiler).
Nesne size sahipse (veya başka bir şekilde varoluş garantisi varsa), başvuruları kullanın T&
.
Uyarı: Akıllı işaretçilerin maliyetlerinin farkında olun. Bellek veya performansla sınırlı ortamlarda, belleği yönetmek için yalnızca daha manuel bir şema ile normal işaretçileri kullanmak yararlı olabilir.
Maliyetler:
- Özel bir silmeniz varsa (örneğin, ayırma havuzları kullanırsanız), bu işaretçi başına manüel olarak silme işleminden kolayca kaçınılabilecek bir ek yüke neden olur.
std::shared_ptr
kopyada bir referans sayımı artışının ek yükü, ayrıca imhada bir azalma ve ardından tutulan nesnenin silinmesiyle 0 sayım denetimi yapılır. Uygulamaya bağlı olarak, bu kodunuzu şişirebilir ve performans sorunlarına neden olabilir.
- Derleme zamanı. Tüm şablonlarda olduğu gibi akıllı işaretçiler de derleme sürelerine olumsuz katkıda bulunur.
Örnekler:
struct BinaryTree
{
Tree* m_parent;
std::unique_ptr<BinaryTree> m_children[2]; // or use std::array...
};
İkili bir ağacın ana ağacı yoktur, ancak bir ağacın varlığı ana ağacının (veya nullptr
kök için) varlığını ima eder , böylece normal bir işaretçi kullanır. İkili bir ağacın (değer semantiği olan) çocuklarının tek mülkiyeti vardır, yani bunlar std::unique_ptr
.
struct ListNode
{
std::shared_ptr<ListNode> m_next;
std::weak_ptr<ListNode> m_prev;
};
Burada, liste düğümü sonraki ve önceki listelerinin sahibidir, bu nedenle bir yön tanımlar ve döngüyü kırmak shared_ptr
için sonraki ve weak_ptr
önceki için kullanırız.