これは、生涯管理を可能にするためです。
制御ブロックは、weak_count
がゼロになるまで破棄されません。オブジェクトstorage
は、count
がゼロになるとすぐに破棄されます。これは、カウントがゼロになると、storage
のデストラクタを直接呼び出す必要があることを意味し、は、コントロールブロックのデストラクタのではありません。
デストラクタを呼び出すコントロールブロックのデストラクタがstorage
でないようにするには、storage
の実際のタイプはT
にできません。
強い参照カウントしかなかった場合、T
は問題なく(しかもはるかに簡単です)。
実際のところ、実装はこれより少し複雑です。 shared_ptrはT
をnew
に割り当ててからshared_ptr
を構築することで構築できます。
template<typename T>
struct shared_ptr_control_block {
std::atomic<long> count;
std::atomic<long> weak_count;
T* ptr;
};
と何make_shared
割り当ては次のとおりです:したがって実際制御ブロックは、より多くのように見える
template<typename T>
struct both {
shared_ptr_control_block cb;
std::aligned_storage_t<sizeof (T), alignof (T)> storage;
};
そしてcb.p
はstorage
のアドレスに設定されています。 both
構造体をmake_shared
に割り当てると、2つではなく1つのメモリ割り当てが行われます(メモリ割り当ては高価です)。
注:shared_ptrデストラクタが制御ブロックがboth
の一部であるかどうかを知る方法が必要です(この場合、完了するまでメモリを解放できません)以前は解放することができます)。これは、シンプルなブールフラグ(この場合、コントロールブロックがより大きい)、またはポインタ内のいくつかのスペアビット(ポータブルではありませんが、標準ライブラリ実装は移植可能である必要はありません)を使用することによって可能です。実装はさらに複雑なポインタにすべての場合はmake_shared
の場合に格納することを避けるために複雑にすることができます。
ああ、わかりました。したがって、参照カウントが1つしかない場合(強いカウント)、 'T'で十分でしょうか? –
@ZizhengTai、yes –
必要なメモリ割り当ての数を減らすために、make_sharedがコントロールブロックとオブジェクトを組み合わせることに言及する価値があります。単純にshared_ptrを構築するには、共有されるオブジェクトに対して1つの割り当てが必要であり、制御ブロックに対して1つの割り当てが必要でした。 –