Sleen
Sleen

Reputation: 39

runtime error when the list.clear() was called

I want to simulate the C# Event-Driven Programming in Windows Programming with C++.

I want to accomplish that in this way :

  1. use a list container to save function pointers
  2. override the += operator, make the class Event can add function in this way event+=handlerFuncName
  3. override the () operator, so we can call the function in list

Event class:

template<class Sender_Type, class Args_Type>
class Event{
private:
    typedef void(*HFUN)(Sender_Type *, Args_Type);
    list<HFUN> handlers;
public:
    void operator +=(HFUN handler){
        handlers.push_back(handler);
    }

    void operator ()(Sender_Type *sender, Args_Type e){       
        for (list<HFUN>::iterator it = handlers.begin(); it != handlers.end(); it++)
            (*it)(sender, e);
    }

    ~Event(){ printf("Release..\n"); }
};

and here is a instance :

the definition of EventArgs class and the window class:

class EventArgs{ };

class Win32Window
{
public:
    // event definition
    Event<Win32Window, EventArgs> Loaded;

    // ctor
    Win32Window(){
        // ...
        // trigger the Loaded event
        Loaded(this, EventArgs());
    }
    // ...
};

the definition of the event handler function:

void Window_Loaded(Win32Window *sender, EventArgs e){
    MessageBox(NULL, "Window_Loaded", "xx", 0);
}

main function:

Win32Window wnd;
//add the event handler function
wnd.Loaded += Window_Loaded;

It works but when the window was closing, there was runtime error in list.clear()! Here is a snapshot of exception:

Upvotes: 0

Views: 198

Answers (1)

Tristan Brindle
Tristan Brindle

Reputation: 16864

This is, I think, precisely the kind of problem that std::function was intended to help with. Try something like this for starters:

#include <functional>
#include <iostream>
#include <vector>

template <typename Sender, typename... Args>
class Event
{
    using FuncType = std::function<void(Sender&, Args...)>;
    std::vector<FuncType> vec;

public:
    Event& operator+=(FuncType f) {
        vec.push_back(f);
        return *this;
    }

    void operator()(Sender& s, Args... a) {
        for (auto& f : vec) {
            f(s, a...);
        }
    }
};


struct Window
{
    Event<Window, int, int> resized;

    void resize(int width, int height) {
        // blah blah
        resized(*this, width, height);
    }

};

int main()
{
    Window w;

    w.resized += [](Window&, int w, int h) {
        std::cout << "Window resized to " << w << " by " << h << std::endl;
    };

    w.resize(800, 600);
}

Note that this method allows you to not only use regular functions as event handers, but also lambdas (as demonstrated), and also function objects.

Upvotes: 1

Related Questions