当不再有引用时,如何从缓存中删除智能指针?

时间:2022-09-09 07:35:57

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.

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

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.

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

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?

我的第一个想法是周期性地遍历缓存并以一个引用计数清除对象。我不喜欢这个想法,因为这是一个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

Cheers Rich

欢呼声丰富

4 个解决方案

#1


9  

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.

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

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.

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

#2


4  

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.

可以使用boost shared_ptr。有了这个,您就可以提供一个自定义删除器(请参见这个,因此请关注如何进行此操作)。在这个自定义删除器中,您知道您已经达到了最后一个引用计数。现在可以从缓存中删除指针。

#3


1  

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

您需要保留缓存弱指针,而不是shared_ptr。

#4


0  

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.

您可能会考虑为您的缓存类编写一个入侵的“弱”ptr。您仍然需要做一些事情来清理缓存中过期的弱指针,但是它并不像清理实际缓存的对象那样重要。

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.

php是发布到boost邮件列表的一个实现。它不是线程安全的,但它可能对你有用。

#1


9  

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.

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

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.

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

#2


4  

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.

可以使用boost shared_ptr。有了这个,您就可以提供一个自定义删除器(请参见这个,因此请关注如何进行此操作)。在这个自定义删除器中,您知道您已经达到了最后一个引用计数。现在可以从缓存中删除指针。

#3


1  

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

您需要保留缓存弱指针,而不是shared_ptr。

#4


0  

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.

您可能会考虑为您的缓存类编写一个入侵的“弱”ptr。您仍然需要做一些事情来清理缓存中过期的弱指针,但是它并不像清理实际缓存的对象那样重要。

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.

php是发布到boost邮件列表的一个实现。它不是线程安全的,但它可能对你有用。