Store Function Pointers to any Member Function

前端 未结 4 1534
太阳男子
太阳男子 2020-12-30 16:59

My Event Manager

For a event manager I need to store many pointers to functions in a vector to call them when the event is triggered. (I will provide the source co

4条回答
  •  天命终不由人
    2020-12-30 17:09

    Not a direct response, so bear with me.

    Before we start: This is generally referred to as the Observer pattern, you might find lots of confused information on the web about it, and many failed implementations, but who knows you might also strike gold.

    Okay, so first the question has a fundamental flaw: it fails to consider that capturing object references is tricky, because object lifetimes are bounded.

    Therefore, even before we delve into the specifics of an implementation we need to ask ourselves how to handle stale references. There are two basic strategies:

    1. Not having stale references, this implies that registered objects unregister themselves automatically upon destruction. The mechanism can be factored out in a base class.

    2. Having a way to tell good and stale references apart when inspecting them, and lazily collecting the stale ones. The mechanism can be enforced using a shared_ptr/weak_ptr pair and realizing that weak_ptr are observers of the shared_ptr.

    Both solutions are viable and neither implementation is perfect. The base class mechanism assumes you can actually modify your class hierarchy while the weak_ptr trick assumes that all observes will be heap-allocated and their lifetime controlled by a weak_ptr.

    I will make an example using shared_ptr (and make use of a number of C++11 facilities, though none is mandatory here):

    class EventManager {
        typedef std::unique_ptr OPtr;
        typedef std::vector Observers;
    public:
    
        // Callback observers of "name"
        // Returns the number of observers so invoked
        size_t signal(std::string const& name) const {
            auto const it = _observers.find(name);
            if (it == _observers.end()) { return 0; }
    
            Observers& obs = it->second;
    
            size_t count = 0;
            auto invoker = [&count](OPtr const& p) -> bool {
                bool const invoked = p->invoke();
                count += invoked;
                return not invoked; // if not invoked, remove it!
            };
    
            obs.erase(std::remove_if(obs.begin(), obs.end(), invoker), obs.end());
    
            if (obs.empty()) { _observers.erase(it); }
    
            return count;
        }
    
        // Registers a function callback on event "name"
        void register(std::string const& name, void (*f)()) {
            _observers[name].push_back(OPtr(new ObserverFunc(f)));
        }
    
        // Registers an object callback on event "name"
        template 
        void register(std::string const& name, std::shared_ptr const& p, void (T::*f)()) {
            _observers[name].push_back(OPtr(new ObserverMember(p, f)));
        }
    
    
    private:
        struct Observer { virtual ~Observer() {} virtual bool invoke() = 0; };
    
        struct ObserverFunc: Observer {
            ObserverFunc(void (*f)()): _f(f) {}
    
            virtual bool invoke() override { _f(); return true; }
    
            void (*_f)();
        };
    
        template 
        struct ObserverMember: Observer {
            ObserverT(std::weak_ptr p, void (T::*f)()): _p(p), _f(f) {}
    
            virtual bool invoke() override {
                std::shared_ptr p = _p.lock();
                if (not p) { return false; }
    
                p->*_f();
                return true;
            }
    
            std::weak_ptr _p;
            void (T::*_f)();
        };
    
        // mutable because we remove observers lazily
        mutable std::unordered_map _observers;
    }; // class EventManager
    

提交回复
热议问题