7

我一直在尝试使用智能指针来升级现有的应用程序,并且我正在尝试克服一个难题。在我的应用程序中,我有一个对象缓存,例如让我们称它们为书籍。现在这个图书缓存是由 ID 请求的,如果它们在缓存中,则返回它们,如果不是,则从外部系统请求对象(慢操作)并添加到缓存中。一旦进入缓存,可以在应用程序中打开许多窗口,每个窗口都可以引用本书。在以前版本的应用程序中,程序员必须维护 AddRef 和 Release,当每个使用 Book 对象的窗口关闭时,最终的 Release(在缓存管理器上)将从缓存中删除对象并删除该对象。

您可能已经在这里发现了链中的薄弱环节,当然是程序员记得调用 AddRef 和 Release。现在我已经转向智能指针 (boost::intrusive) 我不再需要担心调用 AddRef 和 Release。然而这导致了一个问题,缓存有一个对象的引用,所以当最后一个窗口关闭时,缓存不会被通知没有其他人持有引用。

我的第一个想法是定期遍历缓存并清除引用计数为 1 的对象。我不喜欢这个主意,因为它是一个 Order 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

您可以使用boost shared_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是一个发布到 boost 邮件列表的实现。它不是线程安全的,但它可能对你有用。

于 2010-03-05T15:51:58.127 回答