You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现优于为每个事件类型单独维护vector的C++事件系统

优化方案1:使用std::unordered_map替代multimap消除冗余逻辑与性能开销

你之前的multimap实现存在两个明显问题:

  • multimap允许多个相同key的条目,构造函数预插所有事件的逻辑如果后续不小心重复插入,会出现同一个事件对应多份回调列表的bug
  • 每次绑定回调、触发事件都要遍历全表,事件数量多了之后性能会大幅下降

关联容器本身支持O(1)(unordered_map)或O(logn)(map)的key查找,完全不需要自行遍历匹配,同时也不需要提前在构造函数里预插所有事件类型,绑定回调时如果对应事件的回调列表不存在会自动创建:

#include <vector>
#include <unordered_map>
#include <SDL2/SDL.h>

// 可扩展为带事件参数的回调,方便业务逻辑获取事件数据
typedef void(*CALLBACK)(const SDL_Event*);

enum EventType {
    WINDOW_RESIZE = SDL_WINDOWEVENT_RESIZED,
    WINDOW_CLOSE = SDL_QUIT,
    KEY_DOWN = SDL_KEYDOWN,
    KEY_UP = SDL_KEYUP,
    MOUSE_DOWN = SDL_MOUSEBUTTONDOWN,
    MOUSE_UP = SDL_MOUSEBUTTONUP,
    MOUSE_MOVED = SDL_MOUSEMOTION,
    MOUSE_SCROLLED = SDL_MOUSEWHEEL
};

class EventManager {
public:
    void bind(CALLBACK f, EventType type) {
        // 直接索引即可,不存在的key会自动创建空回调列表
        events[type].push_back(f);
    }

    void update() {
        SDL_Event event;
        while (SDL_PollEvent(&event)) {
            // 直接查找当前事件对应的回调列表,找不到直接跳过
            auto it = events.find(static_cast<EventType>(event.type));
            if (it != events.end()) {
                run(it->second, &event);
            }
        }
    }

private:
    void run(const std::vector<CALLBACK>& callbacks, const SDL_Event* event) {
        for (auto cb : callbacks) {
            cb(event);
        }
    }

    // 键为事件类型,值为对应事件的回调列表
    std::unordered_map<EventType, std::vector<CALLBACK>> events;
};

该方案的优势:

  • 新增事件类型无需修改EventManager内部代码,仅需扩展EventType枚举即可,无任何冗余逻辑
  • 回调查找开销从O(n)降到O(1),性能提升明显
  • 无需提前预注册所有事件类型,使用时绑定会自动创建对应条目

优化方案2:支持任意可调用对象的通用版本

如果你的回调需要捕获变量、绑定类成员函数,可以将回调类型替换为std::function,扩展性更强:

#include <functional>
using CALLBACK = std::function<void(const SDL_Event*)>;

// 绑定类成员函数示例
class MyClass {
public:
    void onWindowResize(const SDL_Event* e) {
        // 处理窗口大小变化逻辑
    }
};

// 绑定时用std::bind传递类实例指针
MyClass obj;
eventManager.bind(std::bind(&MyClass::onWindowResize, &obj, std::placeholders::_1), WINDOW_RESIZE);

// 也可直接绑定lambda表达式
eventManager.bind([](const SDL_Event* e){
    printf("窗口大小变化:%d x %d\n", e->window.data1, e->window.data2);
}, WINDOW_RESIZE);

内容的提问来源于stack exchange,提问作者Jaan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 05:39:01