He estado tratando de usar punteros inteligentes para actualizar una aplicación existente, y estoy tratando de superar un acertijo. En mi aplicación tengo un caché de objetos, por ejemplo, vamos a llamarlos libros. Ahora, esta caché de libros se solicita por ID y, si están en la memoria caché, se devuelven; de lo contrario, el objeto se solicita desde un sistema externo (operación lenta) y se agrega a la memoria caché. Una vez en la memoria caché, se pueden abrir muchas ventanas en la aplicación, cada una de estas ventanas puede tomar una referencia al libro. En la versión anterior de la aplicación, el programador tenía que mantener AddRef y Release, cuando cada ventana que utilizaba el objeto Book estaba cerrada, la Versión final (en el administrador de caché) eliminaba el objeto de la memoria caché y eliminaba el objeto.¿Cómo eliminar punteros inteligentes de un caché cuando ya no hay más referencias?
Es posible que haya detectado el eslabón débil de la cadena aquí, por supuesto, el programador recuerda llamar a AddRef y Release. Ahora me he movido a punteros inteligentes (boost :: intrusive) Ya no tengo que preocuparme por llamar a AddRef y Release. Sin embargo, esto genera un problema, la memoria caché tiene una referencia al objeto, por lo que cuando se cierra la ventana final, no se notifica a la memoria caché que nadie más está sosteniendo una referencia.
Mis primeros pensamientos fueron caminar periódicamente la caché y purgar objetos con un recuento de referencia de uno. No me gustó esta idea, ya que era una operación de la Orden N y no me sentía bien. He creado un sistema de devolución de llamada, que es mejor pero no fantástico. He incluido el código para el sistema de devolución de llamada, sin embargo, me preguntaba si alguien tenía una mejor manera de hacerlo.
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
Saludos Rich
Debe hacer que 'BaseObject' no se pueda copiar (declarando, pero sin definir, un constructor de copia privada y un operador de asignación), o hacer que se pueda copiar correctamente de alguna manera. Del mismo modo, 'Book' tiene una semántica de copia peligrosa, que se arregla mejor usando' std :: string' en lugar de una matriz administrada manualmente. –
virtual dtor por favor !!! – curiousguy