私が持っていると言うshared_ptr
カスタムアロケータでとカスタム削除手段。
削除プログラムを保存する場所について話している標準では何も見つかりません。カスタムアロケータが削除プログラムのメモリに使用されることはなく、そうでないこともありません。
これは指定されていませんか、それとも何か不足していますか?
私が持っていると言うshared_ptr
カスタムアロケータでとカスタム削除手段。
削除プログラムを保存する場所について話している標準では何も見つかりません。カスタムアロケータが削除プログラムのメモリに使用されることはなく、そうでないこともありません。
これは指定されていませんか、それとも何か不足していますか?
回答:
C ++ 11のutil.smartptr.shared.const / 9:
効果:オブジェクトpと削除者dを所有するshared_ptrオブジェクトを構築します。2番目と4番目のコンストラクタは、aのコピーを使用して、内部で使用するメモリを割り当てます。
2番目と4番目のコンストラクターには次のプロトタイプがあります。
template<class Y, class D, class A> shared_ptr(Y* p, D d, A a);
template<class D, class A> shared_ptr(nullptr_t p, D d, A a);
最新のドラフトでは、util.smartptr.shared.const / 10は、私たちの目的では同等です。
効果:オブジェクトpと削除者dを所有するshared_ptrオブジェクトを構築します。Tが配列型でない場合、最初と2番目のコンストラクターはpでshared_from_thisを有効にします。2番目と4番目のコンストラクタは、aのコピーを使用して、内部で使用するメモリを割り当てます。例外がスローされると、d(p)が呼び出されます。
したがって、アロケータは、割り当てられたメモリに割り当てる必要がある場合に使用されます。現在の基準と関連する欠陥レポートに基づいて、割り当ては必須ではありませんが、委員会によって想定されます。
インタフェースががshared_ptr
あり、制御ブロックと、すべてのことはありません実装可能にshared_ptr
し、weak_ptr
リンクリストに入れているが、実際にはそのような実装ではありません。さらに、たとえばuse_count
が共有されていると仮定して、表現が変更されました。
削除可能なのは、構成可能オブジェクトのみを移動するためです。したがって、に複数のコピーを持つことはできませんshared_ptr
。
Deleterを特別に設計された場所に配置しshared_ptr
、Special shared_ptr
が削除されたときにそれを移動する実装を想像できます。実装は適合しているように見えますが、特に使用回数に制御ブロックが必要になる可能性があるため、これも奇妙です(おそらく、使用回数で同じことを行うことは可能ですが、さらに奇妙です)。
私が見つけた関連のDR:545、575、2434、(すべての実装が制御ブロックを使用していることを確認幾分それを強制そのマルチスレッド制約を暗示しているように見える)2802デリータのみ構築可能に移動することを必要とする(したがって、実装場所を防ぎ削除者はいくつかshared_ptr
のの間でコピーされます)。
a
を割り当て解除するために同じアロケータ(のコピー)を使用することについて何も見つからないことです。これは、のそのコピーの一部のストレージを意味しますa
。[util.smartptr.shared.dest]にはそれに関する情報はありません。
制御ブロックは、以下を保持する動的に割り当てられたオブジェクトです。
そしてstd :: allocate_sharedから次のようになります:
template< class T, class Alloc, class... Args >
shared_ptr<T> allocate_shared( const Alloc& alloc, Args&&... args );
共有ポインターの制御ブロックとTオブジェクトの両方に1つの割り当てを使用するために、T型のオブジェクトを作成し、それをstd :: shared_ptr [...]でラップします。
だから、のように見えるのstd :: allocate_shared割り当てる必要がありますdeleter
あなたにAlloc
。
編集:n4810
§20.11.3.6 から[util.smartptr.shared.create]
1全てに適用される共通の要件
make_shared
、allocate_shared
、make_shared_default_init
、及びallocate_shared_default_init
過負荷、特に断りのない限り、以下に記載されています。[...]
7備考:(7.1)— 実装は、メモリ割り当てを1つだけ実行する必要があります。[注:これにより、侵入型スマートポインタと同等の効率が得られます。—エンドノート]
[すべてのエンファシス]
したがって、標準では、それstd::allocate_shared
をAlloc
制御ブロックに使用する必要があると述べています。
n4810
回答を見つけて更新しました。
make_shared
であり、コンストラクタ自体についての話ではありません。それでも、小さな削除者のメンバーを使用できます。
これは不特定だと思います。
関連するコンストラクタの仕様は次のとおりです:[util.smartptr.shared.const] / 10
template<class Y, class D> shared_ptr(Y* p, D d); template<class Y, class D, class A> shared_ptr(Y* p, D d, A a); template <class D> shared_ptr(nullptr_t p, D d); template <class D, class A> shared_ptr(nullptr_t p, D d, A a);
効果:
shared_ptr
オブジェクトp
と削除者を所有するオブジェクトを構築しますd
。T
が配列型でない場合、最初のコンストラクタと2番目のコンストラクタはで有効にshared_from_this
なりp
ます。2番目と4番目のコンストラクタはのコピーを使用して、a
内部で使用するメモリを割り当てます。例外がスローされた場合、d(p)
が呼び出されます。
今、私の解釈は、実装が内部使用のためにメモリを必要とするとき、それを使用することによってそれをするということa
です。実装がすべてを配置するためにこのメモリを使用する必要があるという意味ではありません。たとえば、次の奇妙な実装があるとします。
template <typename T>
class shared_ptr : /* ... */ {
// ...
std::aligned_storage<16> _Small_deleter;
// ...
public:
// ...
template <class _D, class _A>
shared_ptr(nullptr_t, _D __d, _A __a) // for example
: _Allocator_base{__a}
{
if constexpr (sizeof(_D) <= 16)
_Construct_at(&_Small_deleter, std::move(__d));
else
// use 'a' to allocate storage for the deleter
}
// ...
};
この実装は「のコピーを使用して、a
内部使用のためにメモリを割り当てますか?」はい、そうです。を使用しない限り、メモリは割り当てられませんa
。この素朴な実装には多くの問題がありますが、それがアロケーターの使用に切り替わったとしましょう。ただし、shared_ptr
はポインターから直接作成され、コピーや移動などの参照は行われず、他の複雑さはありません。重要なのは、有効な実装がそれ自体では理論的に存在できないことを証明できないとは想像できないからです。このような実装が実際に現実の世界で見られると言っているのではなく、標準が積極的にそれを禁止していないように見えるだけです。
shared_ptr
小さな型のIMO は、スタックにメモリを割り当てます。そのため、標準要件を満たしていません
std::move(__d)
、allocate
コピーが必要なときにフォールバックします。