2017-03-10 17 views
1

obj_ref,obj_unrefのオブジェクトが既に参照カウントされている場合(Cのglibのように)。私たちが持っているのは、obj *pのようなポインタです。shared_ptrを使用して、すでに参照カウントされた管理対象オブジェクトを管理する方法は?

私たちは均一なインターフェースを持つために、どのようにオブジェクトを管理するためにC++のshared_ptrを使用できますか?


[OK]を、それは多くの人が私の意図を誤解しているようです。

ここで最大の問題は、削除者ではありません。それは元のマネージャーに、私が参照回数を増やしたという知らせです。

私が割り当てまたはコピーした場合、std::shared_ptrだけが参照カウントを増加しましたが、元のカウントは増加しませんでした。とにかくそれを知らせることはありますか?したがって、非参照操作として。

+0

[どのようにしてstd :: shared \ _ptrを呼び出しませんかdelete()](http://stackoverflow.com/questions/20131877/how-do-you-make-stdshared-ptr-not- call-delete) – user4581301

+1

これはboost :: intrusive_ptrが存在する理由ではありません。 –

+0

@ n.m。 boost :: intrusive_ptrをsupreseedする標準ライブラリにretain_ptrを追加する[proposal](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0468r0.html)もあります。 h –

答えて

-1

複数のスマートポインタインプリメンテーションで同じオブジェクトを持つことは、リファレンスカウントが互いを知ることができないため、非常に悪い考えです。 refカウントが1でゼロになるとすぐに、もう一方がまだrefを保持していてもオブジェクトを削除します。

あなたが本当にカスタムリターナ(何もしていない)を使ってスマートポインタを構築することができたら、本当にこの方法をお勧めしません。

1つの実装を選択してそれに固執します。

+0

あなたのポインタ抽象化が、リリース時のobj_refとobj_unrefを呼び出している場合、元のリフレクションセマンティクスに違反していないことを確かめることができます。 – arithma

2

std::shared_ptrは、所有オブジェクトを破棄する必要があるときに呼び出されるカスタムデリータを渡すことができます。それを使用してobj_unrefに電話することができます。

obj* p = create_obj(); 
p->obj_ref(); 
std::shared_ptr<obj> sp(p, [](auto p) { 
     p->obj_unref(); 
    }); 
/* use sp normally, obj will be 'obj_unref'ed and deleted when sp goes out of scope */ 

私はobjが作成されたのか分からないし、カウントが0に達したときに、それがobj_unref()によって破壊されてしまった場合、私はあなたが私が何を意味するか見たいと考えています。
考え方は、objの内部参照カウントを最初に1回増分し、最後のshared_ptrが破壊されたときに1回だけ減分することです。

+0

shared_ptrをコピーすると、この解決法は* ref *カウントを増やしますか? – virgesmith

+0

それはありません。この考え方は、内部の 'obj' ref coutを最初に1回だけインクリメントし、最後の' shared_ptr'が破棄されたときに1回だけインクリメントすることです。 – alain

0

最も簡単な方法は、何かを壊す可能性が最小限に抑えられた最も侵襲性のないアプローチで、オブジェクトのプライベートメンバーとして自分のファサードを作成し、それにアクセスするための単純なラッパーを提供することです。

次に、std::shared_ptrを使用してください。

1

どういうわけかダクトテープstd::shared_ptrさんのカスタムパーツへの再カウントはしないでください。それはうまく終わらないでしょう。

struct objPtr { 

    objPtr() 
    : _ptr{nullptr} { } 

    objPtr(obj *ptr) 
    : _ptr{ptr} { 
     if(_ptr) 
      _ptr->obj_ref(); 
    } 

    ~objPtr() { 
     if(_ptr) 
      _ptr->obj_unref(); 
    } 

    objPtr(objPtr const &orig) 
    : objPtr{orig._ptr} { } 

    objPtr &operator = (objPtr const &orig) { 
     obj *const oPtr = std::exchange(_ptr, orig._ptr); 

     _ptr->obj_ref(); 
     oPtr->obj_unref(); 

     return *this; 
    } 

    obj &operator *() { return *_ptr; } 
    obj const &operator *() const { return *_ptr; } 

    obj *operator ->() { return _ptr; } 
    obj const *operator ->() const { return _ptr; } 

    operator bool() const { return _ptr; } 
    bool operator !() const { return !_ptr; } 

private: 
    obj *_ptr; 
}; 

必要に応じて移動の構成と割り当てを追加してください。

1

shared_ptrが必要な場合は、unique_ptrで始まります。それから、ビルドアップ。

struct cleanup_obj { 
    // not called with nullptr: 
    void operator()(obj* t)const { 
    obj_unref(t); 
    } 
}; 
using obj_unique_ptr = std::unique_ptr<T, cleanup_obj>; 
using obj_shared_ptr = std::shared_ptr<T>; 
template<class T> 
obj_unique_ptr<T> make_unique_refcount(T* t) { 
    using ptr=obj_unique_ptr<T>; 
    if (!t) return ptr(); 
    obj_ref(t); 
    return ptr(t); 
} 
template<class T> 
obj_shared_ptr<T> make_shared_refcount(T* t) { 
    return make_unique_refcount(t); // implicit convert does right thing 
} 

私は何をしましたか?

最初に私は完成したかもしれないので、unique_ptrラッパーを書いて、unique_ptr-> shared_ptr暗黙の変換によってshared_ptrケースを解決します。

unique_ptrについては、デフォルトのオブジェクト・デストロイヤーを使用していないと言います。この場合、obj_unrefobj*を知っているステートレス関数オブジェクトを使用しています。ステートレス関数オブジェクトは、オーバーヘッドをゼロに保ちます。

nullの場合、最初は参照を追加しません。これは無礼です。

shared_ptrについては、私たちが働いているという事実はunique_ptrです。それは自由な機能になります。 shared_ptrは、unique_ptrが持っている破壊機能を喜んで保存します。 shared_ptrタイプはデフォルトでオブジェクト破壊を消去するので、特別なオブジェクト・デストロイヤーを持っていることを伝える必要はありません。 (これは、が裸のポインタよりもゼロオーバーヘッドであり、shared_ptr<T>は参照カウントブロックの不可避のオーバーヘッドを持っているからです。

私たちのobj_unique_ptr<T>も、裸のポインタに対してゼロオーバーヘッドであることに注意してください。かなり頻繁に、共有されたものの代わりにこれらのうちの1つが必要になります。あなたがしたい場合


さて、あなたは、shared_ptrよりも少ないオーバーヘッドで、押し付けがましいポインタでフルにobj_unique_ptrをアップグレードすることができます。

template<class T> 
struct obj_refcount_ptr : obj_unique_ptr<T> // public 
{ 
    // from unique ptr: 
    obj_refcount_ptr(obj_unique_ptr<T> p):obj_unique_ptr<T>(std::move(p)){} 
    obj_refcount_ptr& operator=(obj_unique_ptr<T> p){ 
    static_cast<obj_unique_ptr<T>&>(*this)=std::move(p); 
    return *this; 
    } 

    obj_refcount_ptr(obj_refcount_ptr&&)=default; 
    obj_refcount_ptr& operator=(obj_refcount_ptr&&)=default; 
    obj_refcount_ptr()=default; 

    obj_refcount_ptr(obj_refcount_ptr const& o): 
    obj_refcount_ptr(make_unique_refcount(o.get()) 
    {} 
    obj_refcount_ptr& operator=(obj_refcount_ptr const& o) { 
    *this = make_unique_refcount(o.get()); 
    return *this; 
    } 
}; 

私はそれをカバーすると思います。これは、割り込み型のスマートポインタをカウントするゼロオーバヘッドのリファレンスです。これらの侵入型スマートポインタは、unique_ptrであるため、暗黙の変換によってstd::shared_ptr<T>に変換することができます。彼らはちょうどunique_ptr私たちは自分自身をコピーするために教えているsです!

obj_refcount_ptrからshared_ptrに移動する必要があります。

operator std::shared_ptr<T>() const { 
    return obj_refcount_ptr(*this); 
} 

*thisobj_refcount_ptrコピーをcreatresとshared_ptrにそれを移動する:私たちは、この問題を解決することができます。 add refは1つだけ呼び出され、remove refはshared_ptrが0になると呼び出されます。


一般的なアプローチは、私たちにshared_ptr、最終的にrefcount_ptrを取得するには、その実装を悪用し、その後、最も単純なスマートポインタ(unique_ptr)で始まる右のそれを取得することです。 unique_ptrの実装を孤立してテストすることができます。その正確さは、より豊富なポインタのテストを容易にします。

関連する問題