Как удалить интеллектуальные указатели из кэша, когда больше нет ссылок?

Я пытался использовать интеллектуальные указатели для обновления существующего приложения, и я пытаюсь преодолеть загадку. В моем приложении у меня есть кэш объектов, например, позволяет, называют их книгами. Теперь этот кэш книг требует идентификатор и если они находятся в кэше, они возвращаются, если не объект требуют от внешней системы (медленная операция) и добавляют к кэшу. Однажды в кэше много окон могут быть открыты в приложении, каждое из этих окон может взять ссылку на книгу. В предыдущей версии приложения программист должен был поддержать AddRef и Выпуск, когда каждое окно с помощью Книжного объекта закрылось, финальная версия (на диспетчере кэша) удалит объект из кэша и удалит объект.

Вы, возможно, определили слабое звено в цепочке здесь, это - конечно, программист, не забывающий назвать AddRef и Выпуск. Теперь я переместился в интеллектуальные указатели (повышение:: навязчивый), я больше не должен волноваться о вызове AddRef и Выпуска. Однако это приводит к проблеме, кэш имеет ссылку на объект, поэтому когда заключительное окно закрывается, кэш не уведомляется, что никто еще не держит ссылку.

Мои первые мысли состояли в том, чтобы периодически обходить кэш и объекты чистки с подсчетом ссылок одного. Мне не нравилась эта идея, поскольку это было операцией Порядка 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

Богатые аплодисменты

7
задан Shalom Craimer 29 April 2012 в 14:39
поделиться

4 ответа

Я никогда не использовал boost::intrusive smart pointers, но если бы вы использовали shared_ptr smart pointers, вы могли бы использовать weak_ptr объекты для вашего кэша.

Эти weak_ptr указатели не считаются ссылкой, когда система решает освободить их память, но могут быть использованы для получения shared_ptr до тех пор, пока объект еще не удален.

9
ответ дан 6 December 2019 в 15:21
поделиться

Вы можете подумать о написании intrusive_weak_ptr для вашего класса кеша. Вам все равно нужно будет время от времени что-то делать, чтобы очищать просроченные слабые указатели в вашем кеше, но это не так важно, как очистка фактических кэшированных объектов.

http://lists.boost.org/boost-users/2008/08/39563.php - это реализация, которая была размещена в списке рассылки boost. Это не потокобезопасно, но может сработать для вас.

0
ответ дан 6 December 2019 в 15:21
поделиться

Вы можете использовать boost shared_ptr . С его помощью вы можете предоставить собственный удалитель (см. этот поток SO о том, как это сделать). И в этом настраиваемом удаленном средстве вы знаете, что достигли последнего счетчика ссылок. Теперь вы можете удалить указатель из кеша.

4
ответ дан 6 December 2019 в 15:21
поделиться

Вам необходимо хранить в кэше слабые указатели вместо shared_ptr.

1
ответ дан 6 December 2019 в 15:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: