std :: make_sharedを使用してvoidポインタを作成したいと思います。 make_sharedはshared_ptr(new T)よりも速いと思われ、例外を保存するmake_sharedの方法でshared_ptr(new foo)を作成するライブラリ関数があるのだろうかと思います。cpp voidポインタのmake_shared
答えて
あなたはmake_shared
に関連した効率の損失なしにshared_ptr<void>
へのshared_ptr<foo>
を変換することができます:
#include <memory>
struct foo {};
int main()
{
std::shared_ptr<void> p = std::make_shared<foo>();
}
変換はあなたが今を経由して、それを参照していても、同じメモリ割り当てでfoo
と参照カウントを保持しますa void*
。
更新
このしくみを教えてください。参照カウントを含む制御ブロックに
+------> foo
| ^
p1 ---------> (refcount, +) |
p2 --- foo* -----------------------+
p1
点(実際には二つの基準カウント:強い所有者のための1つの弱い所有者のためのもの)、削除部
std::shared_ptr<foo>
の一般的な構造は、二つのポインタであります、アロケータ、およびオブジェクトの「動的」型へのポインタを含む。 「ダイナミック」タイプは、shared_ptr<T>
コンストラクタが見たオブジェクトのタイプです。たとえば、Y
(T
と同じでも異なってもよい)です。
p2
はT
はshared_ptr<T>
と同じT
であるT*
を入力しています。これをストアドオブジェクトの「静的な」タイプと考えてください。 shared_ptr<T>
を参照解除すると、逆参照されるのはp2
です。 shared_ptr<T>
を破棄し、参照カウントがゼロになると、制御ブロック内のポインタは、foo
の破壊に役立ちます。
上記の図では、コントロールブロックとfoo
の両方が動的に割り当てられています。 p1
は所有ポインタであり、制御ブロック内のポインタは所有ポインタである。 p2
は所有していないポインタです。 p2
のの機能は参照外です(矢印演算子、get()
など)。
あなたがmake_shared<foo>()
を使用する場合、実装は参照カウントや他のデータと並んで、制御ブロックにfoo
権利を置くための機会を持っています
p1 ---------> (refcount, foo)
p2 --- foo* --------------^
ここでの最適化が唯一の今があるということです単一割り当て:foo
を埋め込む制御ブロック。
上記shared_ptr<void>
に変換される場合、それが起こるすべてである:
p1 ---------> (refcount, foo)
p2 --- void* -------------^
すなわちp2
のタイプはfoo*
からvoid*
に変わります。それでおしまい。 (コピーと一時的な破壊を説明するために参照カウントをインクリメント/デクリメントすることに加えて、それは左辺値から構成することによって省略することができる)。参照カウントがゼロになると、それはp1
で見つけたfoo
を破壊する制御ブロックです。 p2
は破壊操作に参加しません。
p1
は実際にはコントロールブロックの汎用ベースクラスを指しています。この基本クラスは、派生コントロールブロックに格納されている型foo
を無視しています。導出された制御ブロックは、実際のオブジェクトタイプY
がわかっているときにshared_ptr
のコンストラクタで作成されます。しかしその後、shared_ptr
はcontrol_block_base*
を介して制御ブロックとしか通信できません。つまり、破棄のようなものは、仮想関数呼び出しを介して発生します。
shared_ptr<void>
の "move construction"は、C++ 11の右辺値shared_ptr<foo>
から2つの内部ポインタをコピーするだけで、参照カウントを操作する必要はありません。右辺値shared_ptr<foo>
はとにかく離れて行くことを約あるので、これは次のとおりです。
// shared_ptr<foo> constructed and destructed within this statement
std::shared_ptr<void> p = std::make_shared<foo>();
これはshared_ptr
コンストラクタのソースコードの中で最もはっきり見ることができます。
template<class _Tp>
template<class _Yp>
inline _LIBCPP_INLINE_VISIBILITY
shared_ptr<_Tp>::shared_ptr(shared_ptr<_Yp>&& __r,
typename enable_if<is_convertible<_Yp*, _Tp*>::value, __nat>::type)
_NOEXCEPT
: __ptr_(__r.__ptr_),
__cntrl_(__r.__cntrl_)
{
__r.__ptr_ = 0;
__r.__cntrl_ = 0;
}
変換建設する前に参照カウントは1つだけです変換後の参照カウントは依然として1であり、ソースはデストラクタの実行前に何も指していません。これは、一言で言えば、移動セマンティクスの喜びです! :-)
これはどのように機能しますか?コンパイラの最適化(それらに頼ることが嫌い)?私の理解は、純粋なC++では、私が期待することのできる最高のものは、移動セマンティクスであると言います。これを読んで私はもっと複雑なことが起こると期待しています。 – ted
すばらしい詳細と素晴らしい答え!いくつかのオーバーヘッド(私は恐れていた)が残っているように見える(refcountの増加、p2がvoid型の新しい共有ポインタ、p2が実際の型である共有ポインタ(制御ブロックへのポインタ、オブジェクトへのポインタ)の解放)滞在してください。私が間違っているなら、私を訂正してください。 – ted
@ted: 'shared_ptr
- 1. void *ポインタのポインタ演算
- 2. const void *ポインタのctypes
- 3. クローンvoid *型のポインタ
- 4. 関数ポインタが互換性がないポインタ型void(my_type *)からvoid(*)(void *)
- 5. boost :: variantとvoid *ポインタ
- 6. voidポインタとffcallライブラリ
- 7. のvoidポインタのバイト数
- 8. void *とchar *ポインタの算術
- 9. C voidポインタの算術
- 10. voidポインタ関数の出力
- 11. void *ポインタの参照問題?
- 12. 変数をvoidポインタ、またはC++のvoidポインタ参照に送ります
- 13. QBufferからvoidポインタとメモリサイズ
- 14. 特別なポインタ値((void *)1)
- 15. ステートフルC++グローバルvoid関数ポインタ
- 16. は「make_shared」
- 17. バイナリファイルへのvoidポインタの書き込み
- 18. LLVMへのvoidポインタの転送IRBuilder CreateCall
- 19. 構造体へのvoidポインタのキャスト
- 20. 配列へのvoidポインタの使用
- 21. サンプルコードのAVFoundation.Frameworkの静的voidポインタ
- 22. 任意の型ポインタへのvoidポインタのキャスト
- 23. GCC警告:void型のポインタ算術*
- 24. C++ポインタvoid関数の問題
- 25. C++型キャスト:voidポインタからクラスポインタへのポインタをキャスト
- 26. C++でvoidポインタを削除する
- 27. パラメータとして渡しvoidポインタ
- 28. 逆参照 'void *'ポインタについて
- 29. C++でvoidポインタとは何ですか?
- 30. なぜcallocポインタ型がvoid *ですか?
どのような種類のオブジェクトを作成しますか? –
それはsupllyのためにいくつかの異なる構文が必要であるという問題です。 make_void_shared(コンストラクタparams)。私はstatic_pointer_castからパフォーマンスが得られません(make_shared (bar1、...、barn)) –
ted
shared_ptrにvoid *をラップするように求めていますが、実際のオブジェクトを指していますか?しかし、それのポイントは何ですか? –