当没有更多引用时,如何从缓存中删除智能指针?

发布于 2024-08-23 17:50:09 字数 2205 浏览 5 评论 0原文

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

您可能已经在这里发现了链条中的薄弱环节,当然是程序员记得调用 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

干杯 富有的

I've been trying to use smart pointers to upgrade an existing app, and I'm trying to overcome a puzzle. In my app I have a cache of objects, for example lets call them books. Now this cache of books are requested by ID and if they're in the cache they are returned, if not the object is requested from an external system (slow operation) and added to the cache. Once in the cache many windows can be opened in the app, each of these windows can take a reference to the book. In the previous version of the app the programmer had to maintain AddRef and Release, when every window using the Book object was closed, the final Release (on the cache manager) would remove the object from the cache and delete the object.

You may have spotted the weak link in the chain here, it is of course the programmer remembering to call AddRef and Release. Now I have moved to smart pointers (boost::intrusive) I no longer have to worry about calling AddRef and Release. However this leads to a problem, the cache has a reference to the object, so when the final window is closed, the cache is not notified that no-one else is holding a reference.

My first thoughts were to periodically walk the cache and purge objects with a reference count of one. I didn't like this idea, as it was an Order N operation and didn't feel right. I have come up with a callback system, which is better but not fantastic. I have included the code for the callback system, however I was wondering if anyone had a better way of doing this?

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

Cheers
Rich

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

只有一腔孤勇 2024-08-30 17:50:09

我从未使用过 boost::intrusive 智能指针,但如果您使用shared_ptr 智能指针,则可以使用weak_ptr 对象作为缓存。

当系统决定释放其内存时,这些weak_ptr指针不算作引用,但只要该对象尚未被删除,就可以用来检索shared_ptr。

I never used boost::intrusive smart pointers, but if you would use shared_ptr smart pointers, you could use weak_ptr objects for your cache.

Those weak_ptr pointers do not count as a reference when the system decides to free their memory, but can be used to retrieve a shared_ptr as long as the object has not been deleted yet.

你怎么敢 2024-08-30 17:50:09

您可以使用boost shared_ptr。有了这个,您可以提供一个自定义删除器(请参阅 SO线程,了解如何做吧)。在该自定义删除器中,您知道您已达到最后的引用计数。您现在可以从缓存中删除指针。

You can use boost shared_ptr. With this you can provide a custom deleter (see this SO thread on how to do it). And in that custom deleter you know that you have reached the last reference count. You can now remove the pointer from the cache.

优雅的叶子 2024-08-30 17:50:09

您需要在缓存中保留 弱指针的shared_ptr。

You need to keep in your cache weak pointers instead of shared_ptr.

我们只是彼此的过ke 2024-08-30 17:50:09

您可以考虑为您的缓存类编写一个 intrusive_weak_ptr 。您仍然需要不时地清理缓存中过期的弱指针,但这并不像清理实际缓存的对象那么重要。

http://lists.boost.org/boost-users/2008/ 08/39563.php 是发布到 boost 邮件列表的实现。它不是线程安全的,但它可能对你有用。

You might consider writing an intrusive_weak_ptr for your cache class. You will still need to do something to clean out the expired weak pointers in your cache from time to time, but it's not as critical as cleaning up the actual cached objects.

http://lists.boost.org/boost-users/2008/08/39563.php is an implementation that was posted to the boost mailing list. It isn't thread safe, but it might work for you.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文