我正在注册四个回调函数:
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;
}
注册回调函数后,会发生段错误。我把问题缩小到两件事。
首先:排除任何进程函数会导致segfault消失。例如,
// this works
glfwSetMouseButtonCallback(procMouseButton);
//glfwSetMousePosCallback(procMousePosition);
glfwSetCharCallback(procCharInput);
glfwSetKeyCallback(procKeyInput);
// this works also
glfwSetMouseButtonCallback(procMouseButton);
glfwSetMousePosCallback(procMouseButton); // exclude procMousePosition
glfwSetCharCallback(procCharInput);
glfwSetKeyCallback(procKeyInput);
第二个:在弹出或推送单身Engine
中声明的std :: vector时发生Segfault:
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有关,但我不知道如何解决它。任何人都可以解释为什么会发生这种错误吗?
重要说明:
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()
答案 0 :(得分:0)
如果没有看到你的其他程序,就很难说为什么会出现这种情况。这听起来与时间有关。以下是您可以尝试的一些事项:
将断点放在Engine类的构造函数,Input类(任何其他涉及的类)和回调设置代码中。这将告诉您回调是否在他们使用构造的单例之前注册。请注意,断点可能会丢失程序的时间,因此如果一个类首先命中,则可以禁用该断点并重新运行。多次尝试以检查结果是否一致。
是否有理由不能尝试更改指针而不是引用(如“惨败”提及)?
(我写这篇文章时的更新使得这部分不太有用,因为callstack显示它不在构造函数中。)这听起来像回调在一些类的构造期间注册。如果是这样的话:
您可以移动注册调用,以便它们在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
}