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

将const std::function<void()>作为void*传入SDL_AddTimer时崩溃的问题排查

问题原因

崩溃的核心是你传递给SDL_AddTimer的std::function指针指向了一个已经销毁的对象:

  • 在set函数中,你传入的lambda会被隐式转换为std::function<void()>临时对象,这个对象的生命周期只到set函数执行结束为止。
  • 当SDL定时器触发回调时,临时对象早已被销毁,wrapper里访问的是野指针,必然导致崩溃。
  • 另外,你用const_cast去掉const属性是多余的——std::function<void()>的operator()本身是const成员函数,不需要修改对象就能调用。
解决方案

要确保传递给定时器的std::function对象生命周期覆盖定时器的整个运行周期,最简单的方式是把回调函数存储为timer类的成员变量:

class timer {
private:
    std::function<void()> m_callback;
    SDL_TimerID m_timer_id = 0; // 用于存储定时器ID,方便后续取消

public:
    ~timer() {
        if (m_timer_id != 0) {
            SDL_RemoveTimer(m_timer_id);
        }
    }

    void set(uint32_t interval, std::function<void()> fn) {
        // 先移除已有的定时器(如果存在)
        if (m_timer_id != 0) {
            SDL_RemoveTimer(m_timer_id);
        }
        // 将回调存储为成员变量,延长生命周期
        m_callback = std::move(fn);
        // 传递成员变量的地址给SDL_AddTimer
        m_timer_id = SDL_AddTimer(interval, wrapper, reinterpret_cast<void*>(&m_callback));
    }

    static uint32_t wrapper(uint32_t interval, void* param) {
        // 转换回const指针(因为不需要修改回调对象)
        const auto* fn = static_cast<const std::function<void()>*>(param);
        (*fn)();
        return interval;
    }
};
额外注意事项
  • SDL的定时器回调是在独立的线程中执行的,如果后续需要修改或销毁m_callback,必须加线程同步(比如用互斥锁),避免竞态条件。
  • 不要传递临时对象、局部变量的地址给SDL_AddTimer,除非你能保证这些对象在定时器运行期间始终有效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 03:52:42