我正在注册四个回调函数:
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/