Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove (non-intrusive) smart pointers from a cache when there are no more references?

Because of my noob reputation, I cannot reply to this Thread, in specific the accepted answer:

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.

This is certainly an intuitive idea, however, the C++ standard does not support comparison of weak_ptrs, so it cannot be used as key for associative containers. This could be circumvented by implementing a comparison operator for weak_ptrs:

template<class Ty1, class Ty2>
    bool operator<(
        const weak_ptr<Ty1>& _Left,
        const weak_ptr<Ty2>& _Right
    );

The problem with this solution is that

(1) the comparison operator has to obtain ownership for every comparison (i.e. creating shared_ptrs from the weak_ptr refs)

(2) the weak_ptr is not erased from the cache when the last shared_ptr that manages the resource is destroyed, but an expired weak_ptr is kept in the cache.

For (2), we could provide a custom destructor (DeleteThread), however, this would require again to create a weak_ptr from the T* that is to delete, which can then be used to erase the weak_ptr from the cache.

My question would be if there is any better approach to a cache using smart pointers (I am using the VC100 compiler, no boost), or do I simply not get it?

Cheers, Daniel

like image 927
dwn Avatar asked Dec 09 '11 13:12

dwn


1 Answers

A possible solution for what you want to achieve might be

Lets say T is your object and shared_ptr<T> is your shared ptr

  1. Only have regular T* in your cache.
  2. Have a custom deleter for your shared_ptr<T>
  3. Have your custom deleter erase your T* from the cache upon delete.

This way the cache doesn't increase the ref count of your shared_ptr<T> but is notified when the ref count reaches 0.

struct Obj{};

struct Deleter
{
    std::set<Obj*>& mSet;
    Deleter( std::set<Obj*>& setIn  )
        : mSet(setIn) {}

    void operator()( Obj* pToDelete )
    {
        mSet.erase( pToDelete );
        delete pToDelete;
    }
};

int main ()
{

    std::set< Obj* > mySet;
    Deleter d(mySet);
    std::shared_ptr<Obj> obj1 = std::shared_ptr<Obj>( new Obj() , d );
    mySet.insert( obj1.get() );
    std::shared_ptr<Obj> obj2 = std::shared_ptr<Obj>( new Obj() , d );
    mySet.insert( obj2.get() );

    //Here set should have two elements
    obj1 = 0;
    //Here set will only have one element

    return 42;
}
like image 154
parapura rajkumar Avatar answered Sep 25 '22 21:09

parapura rajkumar