7

私は既存のアプリをアップグレードするためにスマートポインターを使用しようとしてきました、そして私はパズルを克服しようとしています。私のアプリにはオブジェクトのキャッシュがあります。たとえば、それらを本と呼びましょう。これで、この本のキャッシュはIDによって要求され、キャッシュ内にある場合は返されます。そうでない場合は、オブジェクトが外部システムから要求され(低速操作)、キャッシュに追加されます。キャッシュに入ると、アプリで多くのウィンドウを開くことができ、これらの各ウィンドウは本への参照を取得できます。以前のバージョンのアプリでは、プログラマーはAddRefとReleaseを維持する必要があり、Bookオブジェクトを使用するすべてのウィンドウが閉じられると、(キャッシュマネージャー上の)最終リリースでオブジェクトがキャッシュから削除され、オブジェクトが削除されました。

ここでチェーンの弱いリンクを見つけたかもしれません。もちろん、プログラマーはAddRefとReleaseを呼び出すことを覚えています。これで、スマートポインター(boost :: intrusive)に移動しました。AddRefとReleaseの呼び出しについて心配する必要はありません。ただし、これは問題につながります。キャッシュにはオブジェクトへの参照があるため、最後のウィンドウを閉じても、他の誰も参照を保持していないことがキャッシュに通知されません。

私の最初の考えは、定期的にキャッシュをウォークし、参照カウントが1のオブジェクトをパージすることでした。これはオーダーNの操作であり、気分が悪いため、私はこのアイデアが気に入らなかった。私はコールバックシステムを思いついた。それはより良いが素晴らしいものではない。コールバックシステムのコードを含めましたが、誰かがこれを行うためのより良い方法があるかどうか疑問に思っていましたか?

class IContainer
{
public:
    virtual void FinalReference(BaseObject *in_obj)=0;
};

class BaseObject 
{
    unsigned int m_ref;

public:
    IContainer *m_container;

    BaseObject() : m_ref(0),m_container(0)
    {
    }

    void AddRef()
    {
        ++m_ref;
    }
    void Release()
    {
        // if we only have one reference left and we have a container
        if( 2 == m_ref && 0 != m_container )
        {
            m_container->FinalReference(this);
        }

        if( 0 == (--m_ref) )
        {
            delete this;
        }
    }
};

class Book : public BaseObject
{
    char *m_name;
public:
    Book()
    {
        m_name = new char[30];
        sprintf_s(m_name,30,"%07d",rand());
    }
    ~Book()
    {
        cout << "Deleting book : " << m_name;
        delete [] m_name;
    }

    const char *Name()
    {
        return m_name;
    }
};

class BookList : public IContainer
{
public:
    set<BookIPtr> m_books;

    void FinalReference(BaseObject *in_obj)
    {
        set<BookIPtr>::iterator it = m_books.find(BookIPtr((Book*)in_obj));
        if( it != m_books.end() )
        {
            in_obj->m_container = 0;
            m_books.erase( it );
        }
    }
};

namespace boost
{
    inline void intrusive_ptr_add_ref(BaseObject *p)
    {
        // increment reference count of object *p
        p->AddRef();
    }
    inline void intrusive_ptr_release(BaseObject *p)
    {
        // decrement reference count, and delete object when reference count reaches 0
        p->Release();
    } 
} // namespace boost

乾杯リッチ

4

4 に答える 4

9

私はboost::intrusiveスマートポインターを使用したことはありませんが、shared_ptrスマートポインターを使用する場合は、キャッシュにweak_ptrオブジェクトを使用できます。

これらのweak_ptrポインタは、システムがメモリを解放することを決定したときに参照としてカウントされませんが、オブジェクトがまだ削除されていない限り、shared_ptrを取得するために使用できます。

于 2010-03-05T12:10:09.467 に答える
4

boostshared_ptrを使用できます。これを使用して、カスタム削除機能を提供できます(これを行う方法については、このSOスレッドを参照してください)。そして、そのカスタム削除機能では、最後の参照カウントに到達したことがわかります。これで、ポインタをキャッシュから削除できます。

于 2010-03-05T12:12:58.980 に答える
1

shared_ptrではなく、弱ポインタ​​ーをキャッシュに保持する必要があります。

于 2010-03-05T12:14:23.637 に答える
0

キャッシュクラスにintrusive_weak_ptrを作成することを検討してください。キャッシュ内の期限切れのウィークポインタをときどきクリーンアップするために何かを行う必要がありますが、実際にキャッシュされたオブジェクトをクリーンアップするほど重要ではありません。

http://lists.boost.org/boost-users/2008/08/39563.phpは、ブーストメーリングリストに投稿された実装です。スレッドセーフではありませんが、うまくいくかもしれません。

于 2010-03-05T15:51:58.127 に答える