健壮的C++;事件模式 < P>我已经加入了一个简单的C++事件模式,它允许以下内容: struct Emitter { Event<float> ev; void triggerEvent() { ev.fire(42.0); } }; struct Listener { void gotEvent(float x) { ... } }; int main() { // event source and listener unaware of each other's existence Emitter emitter(); Listener listener(); // hook them up emitterA.ev.addSubscriber(&listener, &Listener::gotEvent); { Listener listener2(); emitter.ev.addSubscriber(&listener2, &Listener::gotEvent); emitter.triggerEvent(); emitter.ev.removeSubscriber(&listener2); // ^ PROBLEM! } emitter.triggerEvent(); emitter.ev.removeSubscriber(&listener1); } struct发射器{ 事件ev; void triggerEvent(){ev.fire(42.0);} }; 结构侦听器{ void gotEvent(float x){…} }; int main(){ //事件源和侦听器不知道彼此的存在 发射极发射极(); 监听器(); //把它们挂起来 emitterA.ev.addSubscriber(&listener,&listener::gotEvent); { 监听器监听器2(); emitter.ev.addSubscriber(&listener2,&Listener::gotEvent); triggerEvent(); 发射器、电动汽车移除订户和监听器2; //问题! } triggerEvent(); 发射器、电动汽车移除订户和监听器1; }

健壮的C++;事件模式 < P>我已经加入了一个简单的C++事件模式,它允许以下内容: struct Emitter { Event<float> ev; void triggerEvent() { ev.fire(42.0); } }; struct Listener { void gotEvent(float x) { ... } }; int main() { // event source and listener unaware of each other's existence Emitter emitter(); Listener listener(); // hook them up emitterA.ev.addSubscriber(&listener, &Listener::gotEvent); { Listener listener2(); emitter.ev.addSubscriber(&listener2, &Listener::gotEvent); emitter.triggerEvent(); emitter.ev.removeSubscriber(&listener2); // ^ PROBLEM! } emitter.triggerEvent(); emitter.ev.removeSubscriber(&listener1); } struct发射器{ 事件ev; void triggerEvent(){ev.fire(42.0);} }; 结构侦听器{ void gotEvent(float x){…} }; int main(){ //事件源和侦听器不知道彼此的存在 发射极发射极(); 监听器(); //把它们挂起来 emitterA.ev.addSubscriber(&listener,&listener::gotEvent); { 监听器监听器2(); emitter.ev.addSubscriber(&listener2,&Listener::gotEvent); triggerEvent(); 发射器、电动汽车移除订户和监听器2; //问题! } triggerEvent(); 发射器、电动汽车移除订户和监听器1; },c++,c++11,events,design-patterns,C++,C++11,Events,Design Patterns,问题是,开发人员需要手动删除每个订阅服务器,否则事件的fire()在遍历每个订阅服务器上的所有订阅服务器时,最终将触发对象上的方法,该对象可能存在,也可能不存在 以下是完整的代码以及一个工作示例: 我将为子孙后代粘贴以下内容 如果我把冒犯的第99行注释掉,它仍然有效!但这显然只是因为内存尚未被覆盖 这是一种危险的虫子,因为它可能处于休眠状态 我怎么能以这样一种方式编写代码,而不让我暴露在这个潜在的UB bug面前 有没有办法把我的电话号码改成35 template<class... Arg

问题是,开发人员需要手动删除每个订阅服务器,否则事件的fire()在遍历每个订阅服务器上的所有订阅服务器时,最终将触发对象上的方法,该对象可能存在,也可能不存在

以下是完整的代码以及一个工作示例:

我将为子孙后代粘贴以下内容

如果我把冒犯的第99行注释掉,它仍然有效!但这显然只是因为内存尚未被覆盖

这是一种危险的虫子,因为它可能处于休眠状态

我怎么能以这样一种方式编写代码,而不让我暴露在这个潜在的UB bug面前

有没有办法把我的电话号码改成35

template<class... Args> 
class Event {
    :
    void fire(Args... args) {
        for( auto& f : subscribers )
            f->call(args...);
模板
班级活动{
:
无效火(Args…Args){
对于(自动和自动:订户)
f->调用(args…);
可以检测每个订户是否仍然存在

在保留发射器和订户不知道对方存在的事实的同时

完整列表:

#include <vector>
#include <iostream>
#include <algorithm>
#include <memory>

using namespace std;

template<class... Args> 
class SubscriberBase {
public:
    virtual void call(Args... args) = 0;
    virtual bool instanceIs(void* t) = 0;
    virtual ~SubscriberBase() { };
};

template<class T, class... Args> 
class Subscriber : public SubscriberBase<Args...> {
private:
    T* t;
    void(T::*f)(Args...);
public:
    Subscriber(T* _t, void(T::*_f)(Args...)) : t(_t), f(_f)  { }
    void call(Args... args)   final  { (t->*f)(args...); }
    bool instanceIs(void* _t) final  { return _t == (void*)t; }
    ~Subscriber()             final  { cout << "~Subscriber() hit! \n"; }
};

template<class... Args> 
class Event {
private:
    using SmartBasePointer = unique_ptr<SubscriberBase<Args...>>;
    std::vector<SmartBasePointer> subscribers;
public:
    void fire(Args... args) {
        for( auto& f : subscribers )
            f->call(args...);
    }

    template<class T> 
    void addSubscriber( T* t, void(T::*f)(Args... args) ) {
        auto s = new Subscriber <T, Args...>(t, f);
        subscribers.push_back(SmartBasePointer(s));
    }

    template<class T> 
    void removeSubscriber(T* t) {
        auto to_remove = std::remove_if(
            subscribers.begin(), 
            subscribers.end(),  
            [t](auto& s) { return s->instanceIs((void*)t); }
            );
        subscribers.erase(to_remove, subscribers.end()); 
    }
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

// example usage:
class Emitter {
private:
    string name;
public:    
    Event<float> eventFloat;
    Event<bool, int> eventB;

    Emitter(string _name) : name(_name) { }

    void triggerEvent() { 
        cout << name << "::triggerEvent() ~ Firing event with: 42\n";
        eventFloat.fire(42.0f); 
    }
};

struct Listener {
    string name;
    Listener(string _name) 
        : name(_name)  { 
        cout << name << "()\n";
    }
    ~Listener() { 
        cout << "~" << name << "()\n";
        //emitter.eventFloat.removeSubscriber(this); 
    }

    void gotEvent(float x) { cout << name <<"::gotEvent hit with value: " << x << endl; }
};

int main() {
    // event source and listener unaware of each other's existence
    Emitter emitterA("emitterA"); 
    Listener listener1("listener1");

    // hook them up
    emitterA.eventFloat.addSubscriber(&listener1, &Listener::gotEvent);
    {
        Listener listener2("listener2");
        emitterA.eventFloat.addSubscriber(&listener2, &Listener::gotEvent);
        emitterA.triggerEvent();
        //emitterA.eventFloat.removeSubscriber(&listener2); // hmm this is awkward
    }

    emitterA.triggerEvent();

    emitterA.eventFloat.removeSubscriber(&listener1); 
    emitterA.triggerEvent();

    return 0;
}
#包括
#包括
#包括
#包括
使用名称空间std;
模板
类SubscriberBase{
公众:
虚拟无效调用(Args…Args)=0;
虚拟布尔实例(void*t)=0;
虚拟~SubscriberBase(){};
};
模板
类订阅者:publicsubscriberbase{
私人:
T*T;
无效(T::*f)(参数…);
公众:
订阅者(T*\U T,void(T::*\U f)(Args…):T(\U T),f(\U f){}
无效调用(Args…Args)最终{(t->*f)(Args…;}
bool instanceIs(void*)final{return{t==(void*)t;}
~Subscriber()最终{cout调用(args…);
}
模板
void addSubscriber(T*T,void(T::*f)(Args…Args)){
自动s=新用户(t,f);
订阅服务器。推回(SmartBasePointer);
}
模板
无效删除订阅方(T*T){
自动删除=标准::删除(
订阅服务器。begin(),
subscribers.end(),
[t] (auto&s){returns s->instanceIs((void*)t);}
);
删除(要删除,请使用subscribers.end());
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
//用法示例:
类发射器{
私人:
字符串名;
公众:
事件浮动;
事件b;
发射器(字符串_name):名称(_name){}
void triggerEvent(){

cout如果对象不“知道”它们的存在,您可以简单地将您想要的副作用编码到侦听器虚拟基析构函数中,以便在它离开作用域时取消注册自身

回调API是一个“C”类结构。为了桥接C++,需要提供实例上下文和回调方法。或者关心客户机类型,它只需要传回注册中给出的相同void*\t。 这使main()能够将&listener1“This”指针注册为引用


将Listener::getEvent()转换为“C”样式静态方法,它接受一些空洞*指针,然后将其转换成侦听器对象,并在处理事件之前使用它来确定对象存在。一个私有的、静态的STD::设置容器将很方便地验证。这安全地将桥完成到C++域。

< P>我已经在这里描述了我的解决方案:

#包括
#包括
#包括
#包括
#包括
使用名称空间std;
//事件包含订阅者的向量
//当它开火时,每个都被调用
模板
类SubscriberBase{
公众:
虚拟无效调用(Args…Args)=0;
虚拟布尔实例(void*t)=0;
虚拟~SubscriberBase(){};
};
模板
类订阅者:publicsubscriberbase{
私人:
T*T;
无效(T::*f)(参数…);
公众:
订阅者(T*\U T,void(T::*\U f)(Args…):T(\U T),f(\U f){}
无效调用(Args…Args)最终{(t->*f)(Args…;}
bool instanceIs(void*)final{return{t==(void*)t;}
~Subscriber()最终{cout调用(args…);
}
模板
void addSubscriber(T*T,void(T::*f)(Args…Args)){
自动s=新用户(t,f);
订阅服务器。推回(SmartBasePointer);
}
//模板
无效删除订户(无效*t)最终{
自动删除=标准::删除(
订阅服务器。begin(),
subscribers.end(),
[t] (自动&s){返回s->instanceIs(t);}
);
删除(要删除,请使用subscribers.end());
}
};
//派生侦听器类:struct MyListener:EventListener,即CRTP
模板
类EventListener{
私人:
//所有订阅我们的活动。。。
向量事件;
公众:
模板
void connect(事件和ev,void(派生::*listenerMethod)(Args…Args)){
ev.addSubscriber((派生*)this,listenerMethod);
事件。推回(&ev);
}
//…当侦听器死亡时,我们必须通知他们所有人删除订阅
~EventListener(){
用于(自动和e:事件)
e->删除订户((作废*)此项);
}
};
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
//用法示例:
类发布者{
私人:
字符串名;
公众:
事件ev
#include <vector>
#include <iostream>
#include <algorithm>
#include <memory>
#include <string>

using namespace std;

// an event holds a vector of subscribers
// when it fires, each is called

template<class... Args>
class SubscriberBase {
public:
    virtual void call(Args... args) = 0;
    virtual bool instanceIs(void* t) = 0;
    virtual ~SubscriberBase() { };
};

template<class T, class... Args>
class Subscriber : public SubscriberBase<Args...> {
private:
    T* t;
    void(T::*f)(Args...);
public:
    Subscriber(T* _t, void(T::*_f)(Args...)) : t(_t), f(_f) { }
    void call(Args... args)   final { (t->*f)(args...); }
    bool instanceIs(void* _t) final { return _t == (void*)t; }
    ~Subscriber()             final { cout << "~Subscriber() hit! \n"; }
};

// our Listener will derive from EventListener<Listener>
// which holds a list of a events it is subscribed to.
// As these events will have different sigs, we need a base-class.
// We will store pointers to this base-class.
class EventBase { 
public:
    virtual void removeSubscriber(void* t) = 0;
};

template<class... Args>
class Event : public EventBase {
private:
    using SmartBasePointer = unique_ptr<SubscriberBase<Args...>>;
    std::vector<SmartBasePointer> subscribers;
public:
    void fire(Args... args) {
        for (auto& f : subscribers)
            f->call(args...);
    }

    template<class T>
    void addSubscriber(T* t, void(T::*f)(Args... args)) {
        auto s = new Subscriber <T, Args...>(t, f);
        subscribers.push_back(SmartBasePointer(s));
    }

    //template<class T>
    void removeSubscriber(void* t) final {
        auto to_remove = std::remove_if(
            subscribers.begin(),
            subscribers.end(),
            [t](auto& s) { return s->instanceIs(t); }
        );
        subscribers.erase(to_remove, subscribers.end());
    }
};

// derive your listener classes: struct MyListener : EventListener<MyListener>, i.e. CRTP
template<class Derived>
class EventListener {
private:
    // all events holding a subscription to us...
    std::vector<EventBase*> events;

public:
    template<class... Args>
    void connect(Event<Args...>& ev, void(Derived::*listenerMethod)(Args... args)) {
        ev.addSubscriber((Derived*)this, listenerMethod);
        events.push_back(&ev);
    }

    // ...when the listener dies, we must notify them all to remove subscription
    ~EventListener() {
        for (auto& e : events)
            e->removeSubscriber((void*)this);
    }
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

// example usage:
class Publisher {
private:
    string name;
public:
    Event<float> eventFloat;
    Event<bool, int> eventB;

    Publisher(string _name) : name(_name) { }

    void triggerEvent() {
        cout << name << "::triggerEvent() ~ Firing event with: 42\n";
        eventFloat.fire(42.0f);
    }
};

struct Listener : EventListener<Listener> {
    string name;
    Listener(string _name)
        : name(_name) {
        cout << name << "()\n";
    }
    ~Listener() {
        cout << "~" << name << "()\n";
        //emitter.eventFloat.removeSubscriber(this); 
    }

    void gotEvent(float x) { cout << name << "::gotEvent hit with value: " << x << endl; }
};

int main() {
    // event source and listener unaware of each other's existence
    Publisher publisherA("publisherA");

    Listener listener1("listener1");
    listener1.connect(publisherA.eventFloat, &Listener::gotEvent);

    {
        Listener listener2("listener2");
        listener2.connect(publisherA.eventFloat, &Listener::gotEvent);

        publisherA.triggerEvent();
    }

    publisherA.triggerEvent();

    return 0;
}