unique_ptr
と shared_ptr
はどちらも、所有するオブジェクトを呼び出すカスタムデストラクタを受け入れます。ただし、unique_ptr
の場合、デストラクタはクラスのテンプレートパラメータとして渡されますが、shared_ptr
のタイプはカスタムデストラクタは、コンストラクタのテンプレートパラメータとして指定されます。
template <class T, class D = default_delete<T>>
class unique_ptr
{
unique_ptr(T*, D&); //simplified
...
};
そして
template<class T>
class shared_ptr
{
template<typename D>
shared_ptr(T*, D); //simplified
...
};
なぜそんな違いがあるのかわかりません。何が必要ですか?
テンプレート引数として削除機能を指定した場合(unique_ptr
のように)、削除機能は型の一部であり、この型のオブジェクトに追加のものを格納する必要はありません。 (shared_ptr
のように)deleterがコンストラクターの引数として渡される場合は、それをオブジェクトに格納する必要があります。同じタイプのオブジェクトに異なる削除機能を使用できるため、これは柔軟性を高めるためのコストです。
これが理由だと思います。unique_ptr
は、オーバーヘッドがゼロの非常に軽量なオブジェクトであると想定されています。 unique_ptr
ごとに削除機能を保存すると、サイズが2倍になる可能性があります。そのため、人々は代わりに古き良き生のポインタを使用するでしょう、それは間違っているでしょう。
一方、shared_ptr
は、参照カウントを保存する必要があるため、それほど軽量ではありません。したがって、カスタム削除機能を保存することも、適切なトレードオフのように見えます。
異なるタイプの共有ポインタは、同じオブジェクトの所有権を共有できます。 overload(8) of std::shared_ptr::shared_ptr
を参照してください。一意のポインタは共有しないため、このようなメカニズムは必要ありません。
template< class Y >
shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;
削除機能をタイプ消去しないと、そのようなshared_ptr<T, Y_Deleter>
をshared_ptr<T>
として使用できなくなり、基本的に役に立たなくなります。
なぜあなたはそのような過負荷が欲しいのですか?
検討する
struct Member {};
struct Container { Member member };
Container
を使用しているときに、Member
を存続させたい場合は、次のことができます。
std::shared_ptr<Container> pContainer = /* something */
std::shared_ptr<Member> pMember(pContainer, &pContainer->member);
pMember
を保持するだけで済みます(おそらくそれをstd::vector<std::shared_ptr<Member>>
に入れます)
または、代わりに、過負荷を使用します(9)
template< class Y >
shared_ptr( const shared_ptr<Y>& r ) noexcept;
// Only exists if Y* is implicitly convertible to T*
あなたは多形の共有を持つことができます
struct Base {};
struct Derived : Base {};
void operate_on_base(std::shared_ptr<Base>);
std::shared_ptr<Derived> pDerived = /* something*/
operate_on_base(pDerived);