J'ai essayé d'utiliser des pointeurs intelligents pour mettre à jour une application existante, et j'essaie de surmonter un casse-tête. Dans mon application, j'ai un cache d'objets, par exemple, appelons les livres. Maintenant, ce cache de livres est demandé par ID et s'ils sont dans le cache, ils sont retournés, sinon l'objet est demandé à partir d'un système externe (opération lente) et ajouté au cache. Une fois dans le cache de nombreuses fenêtres peuvent être ouvertes dans l'application, chacune de ces fenêtres peut prendre une référence au livre. Dans la version précédente de l'application, le programmeur devait maintenir AddRef et Release, lorsque chaque fenêtre utilisant l'objet Book était fermée, la version finale (sur le gestionnaire de cache) supprimait l'objet du cache et supprimait l'objet.Comment supprimer des pointeurs intelligents d'un cache lorsqu'il n'y a plus de références?
Vous avez peut-être repéré le maillon faible de la chaîne ici, c'est bien sûr le programmeur qui se souvient d'appeler AddRef et Release. Maintenant, je suis passé aux pointeurs intelligents (boost :: intrusive) Je n'ai plus à m'inquiéter d'appeler AddRef et Release. Cependant, cela conduit à un problème, le cache a une référence à l'objet, donc quand la fenêtre finale est fermée, le cache n'est pas averti que personne d'autre ne détient une référence. Mes premiers réflexions ont été de parcourir périodiquement le cache et de purger les objets avec un nombre de références égal à 1. Je n'ai pas aimé cette idée, car c'était une opération de l'Ordre N et je ne me sentais pas bien. J'ai mis au point un système de rappel, ce qui est mieux mais pas fantastique. J'ai inclus le code pour le système de rappel, mais je me demandais si quelqu'un avait une meilleure façon de le faire?
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
Vive Rich
Vous devriez rendre 'BaseObject' uncopyable (en déclarant, mais ne définissant pas, un constructeur de copie privée et un opérateur d'affectation), ou le rendre correctement copiable d'une certaine façon. De même, 'Book' a une sémantique de copie dangereuse, qui est mieux fixée en utilisant' std :: string' à la place d'un tableau géré manuellement. –
dtor virtuel s'il vous plaît !!! – curiousguy