/* \file Test callback idiom. This is similar to what might be used in caller-callee pattern, observer-observable pattern, etc. */ #include <iostream> #include <list> #include <memory> #include "BLink.hh" #include "BLinkable.hh" #include "OwnedPtr.hh" using namespace MangoPtr; struct Callee; struct Caller; typedef BLink<const Callee> CalleePtr; int created = 0; int deleted = 0; /* Class that registers itself to caller for notification events. */ struct Callee: public BLinkable<> { const int id; Callee(): id(++created) { std::cout << "Callee " << id << " being created" << std::endl;} ~Callee() { deleted ++; std::cout << "Callee " << id << " being destroyed" << std::endl; } void registerSelf(Caller&) const; void notifyChange() const { std::cout << "Callee " << id << " heard notification" << std::endl; } private: Callee(const Callee& rhs); }; /* Caller does stuff, and calls callees when something happens. */ struct Caller { std::list<CalleePtr> callees; void registerCallee(const CalleePtr& callee) { assert(callee.isNotNull()); callees.push_back(callee); } void notifyCallees() const { for (std::list<CalleePtr>::const_iterator ii = callees.begin(); ii != callees.end(); ++ii) { if (ii->isNotNull()) (*ii)()->notifyChange(); else std::cout << "Callee no longer exists, not notifying" << std::endl; } } }; void Callee::registerSelf(Caller& caller) const { // don't want to bother with a cloner caller.registerCallee(CalleePtr(*this)); } int main() { // create caller: Caller caller; // create callees: typedef Owned<Callee*, OShared> CalleeOwned; std::list<CalleeOwned> callees; for (int i=0; i<5; ++i) { // Safely create and register one callee. Naturally, // a Owned could be used instead of std::auto_ptr std::auto_ptr<Callee> callee(new Callee); assert(callee->getValidityOwner().isValid()); callee->registerSelf(caller); // now add it to list without copy //cout << "Creating empty owner on list" << endl; callees.push_back(CalleeOwned()); assert( isNotNull(callee.get()) ); const int saveDeleted = deleted; //cout << "Taking ownership of " << callee.get() << endl; callees.back().takeOwnership( callee ); assert( isNull(callee.get()) ); assert( saveDeleted == deleted ); assert( isNotNull( callees.back()() ) ); assert( callees.back().isNotNull() ); } // discard the first and last Callees so caller really shows its stuff callees.pop_front(); callees.pop_back(); // create notification event caller.notifyCallees(); }