Ich habe versucht, intelligente Zeiger zu verwenden, um eine vorhandene App zu aktualisieren, und ich versuche, ein Rätsel zu überwinden. In meiner App habe ich einen Cache von Objekten, zum Beispiel können wir sie Bücher nennen. Nun wird dieser Büchercache nach ID angefordert und wenn sie im Cache sind, werden sie zurückgegeben, wenn das Objekt nicht von einem externen System angefordert wird (langsamer Vorgang) und dem Cache hinzugefügt wird. Sobald im Cache viele Fenster in der App geöffnet werden können, kann jedes dieser Fenster einen Verweis auf das Buch nehmen. In der vorherigen Version der App musste der Programmierer AddRef und Release beibehalten, wenn jedes Fenster, das das Book-Objekt verwendete, geschlossen wurde, würde das endgültige Release (auf dem Cache-Manager) das Objekt aus dem Cache entfernen und das Objekt löschen.Wie entferne ich Smart Pointer aus einem Cache, wenn keine Referenzen mehr vorhanden sind?
Vielleicht haben Sie hier die schwache Verbindung in der Kette entdeckt, natürlich erinnert sich der Programmierer daran, AddRef und Release aufzurufen. Jetzt bin ich zu Smartpointern (boost :: intrusiv) übergegangen. Ich muss mir keine Sorgen mehr machen über AddRef und Release. Dies führt jedoch zu einem Problem, da der Cache einen Verweis auf das Objekt hat. Wenn das letzte Fenster geschlossen wird, wird der Cache daher nicht benachrichtigt, dass kein anderer Benutzer eine Referenz hält.
Meine ersten Gedanken waren, den Cache regelmäßig zu durchlaufen und Objekte mit einer Referenzzahl von eins zu löschen. Mir gefiel diese Idee nicht, da es sich um eine Order-N-Operation handelte und ich mich nicht richtig fühlte. Ich habe ein Callback-System entwickelt, das besser, aber nicht fantastisch ist. Ich habe den Code für das Rückrufsystem eingefügt, aber ich fragte mich, ob jemand einen besseren Weg hatte, dies zu tun?
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
Prost Reiche
Sie sollten "BaseObject" nicht kopierbar machen (indem Sie einen privaten Kopierkonstruktor und einen Zuweisungsoperator deklarieren, aber nicht definieren), oder es in irgendeiner Weise korrekt kopierbar machen. Ebenso hat 'Book' eine gefährliche Kopiesemantik, die am besten mit' std :: string' anstelle eines manuell verwalteten Arrays behoben wird. –
virtuelle dtor bitte !!! – curiousguy