c++ - 注册回调函数后出现段错误

标签 c++ segmentation-fault

我正在注册四个回调函数:

glfwSetMouseButtonCallback(procMouseButton);
glfwSetMousePosCallback(procMousePosition);
glfwSetCharCallback(procCharInput);
glfwSetKeyCallback(procKeyInput);

每个回调函数看起来都类似于:

void GLFWCALL procMouseButton(int button, int action) { 
    Input::instance().processMouseButton(button, action); // doesn't do anything yet
}

Input 是单例:

Input& Input::instance()
{
    static Input instance;
    return instance;
}

注册回调函数后,发生段错误。我已将问题缩小为两件事。

首先:排除任何进程函数都会导致段错误消失。例如,

// this works
glfwSetMouseButtonCallback(procMouseButton);
//glfwSetMousePosCallback(procMousePosition);
glfwSetCharCallback(procCharInput);
glfwSetKeyCallback(procKeyInput);

// this works also
glfwSetMouseButtonCallback(procMouseButton);
glfwSetMousePosCallback(procMouseButton); // exclude procMousePosition
glfwSetCharCallback(procCharInput);
glfwSetKeyCallback(procKeyInput);

第二:当弹出或推送一个在单例中声明的 std::vector 时会发生段错误 Engine:

class Engine
{
    public:
        static Engine& instance();

        std::list<GameState*> states;
    private:
        Engine() {}
        Engine(Engine const& copy);
        Engine& operator=(Engine const& copy);
};

// either causes segfault after registering functions
Engine::instance().states.push_back(NULL);
Engine::instance().states.pop_front();

我完全不知所措。我假设问题与 static initialization order fiasco 有关,但我不知道如何修复它。谁能解释为什么会出现此错误?

重要提示:

  • 如果我颠倒链接顺序,它就不会再出现段错误。
  • 我正在使用 MinGW/GCC 进行编译。
  • 我正在运行单线程。
  • 单例没有默认构造函数,一切都由 Singleton::instance().initialize();
  • 初始化
  • 确切的段错误调用堆栈:
0047B487    std::__detail::_List_node_base::_M_hook(std::__detail::_List_node_base*) ()
00000000    0x00401deb in std::list >::_M_insert()
00000000    0x00401dbb in std::list >::push_back()
00401D92    Engine::pushState(GameState*) ()
00404710    StartupState::initialize() ()
00402A11    Engine::initialize() ()
00000000    0x00403f29 in main()

最佳答案

如果没有看到程序的其余部分,很难说出它为什么会出现段错误。这听起来与时间有关。以下是您可以尝试的几件事:

  • 在 Engine 类、Input 类(任何其他涉及的类)和回调设置代码的构造函数中放置断点。这将告诉您回调是否在它们使用的单例构造之前注册。请注意,断点可能会影响程序的计时,因此如果一个类首先命中,您可以禁用该断点并重新运行。多次尝试此操作以检查结果是否一致。

  • 您是否有理由不能尝试更改为指针而不是引用(如提到的“惨败”)?

(我写这篇文章时你的更新使得这部分不太有用,因为调用堆栈显示它不在构造函数中。)这听起来像是回调在某个类的构造过程中注册。如果是这样的话:

  • 您能否移动注册调用以便它们在 main() 下发生?这应该能让你通过初始化。

  • 将类构造分为两个阶段:普通构造函数和 init() 函数。将关键代码放在 init() 中,并在每个人 构建完成后调用它。

您还可以防止回调发生到以后。如果您不能将回调注册移到游戏启动的稍后时间,您可以放置​​标志,以便它们在“安全”时间之前不做任何事情。调整此标志启用的时间可以让您看到“多晚”是“足够晚”。额外的 if() 开销总比崩溃好。 :)

volatile bool s_bCallbackSafe = false;    // set this at some point in your game/app

void GLFWCALL procMouseButton(int button, int action) {
    if (s_bCallbackSafe)
        Input::instance().processMouseButton(button, action); // doesn't do anything yet
}

关于c++ - 注册回调函数后出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10082592/

相关文章:

c++ - 比较最后一个字符,不区分大小写(使用谓词?)

c++ - 在参数中指定数组大小有什么作用吗?

python - Blender:分段,故障核心转储?

c - 尝试访问 sbrk 可用空间的梯子部分后出现段错误

c - 为什么将我的输入分配给枚举会导致段错误?

c - 段错误 SEGV_ACCERR - 对象的无效权限

c++ - 显式类型转换与使用类型规则

c++ - 如何在函数指针列表上使用 std::for_each

c++ - 将 Polycode 链接到 C++

c++ - 导致段错误的 vector 或元素?