[英]Using std::bind and std::function with a class member causes the callback to use an old object reference?
[英]Registering a class member function as a callback to a function using std::bind
我试图将一个类成员函数注册为(常规)回调函数。 除非我误解了某些内容,否则应该可以使用std :: bind(使用C ++ 11)来实现。 我通过以下方式执行此操作:
std::function<void (GLFWwindow*, unsigned int)> cb = std::bind(&InputManager::charInputCallback, this, std::placeholders::_1, std::placeholders::_2);
我的回调函数是通过以下方式定义的:
void InputManager::charInputCallback(GLFWwindow* window, unsigned int key)
使用随机数据创建后,我可以立即测试cb
:
cb(NULL, 0x62);
我可以通过从其中打印到终端来确认此数据已正确发送到回调函数。
但是,我想将此函数注册到GLFW,以便程序窗口的按键被发送到回调函数。 我这样做是这样的:
glfwSetCharCallback(window, (GLFWcharfun) &cb);
就像我之前说过的:手动调用它就可以了。 但是,当我将其注册为回调函数时,每当我按下一个键并且GLFW尝试调用回调函数时,都会出现分段错误。
std :: bind不是我要的内容吗? 我使用不正确吗?
编辑:我不认为这个问题是重复的, 我该如何传递类成员函数作为回调? 就像它已经被确定为一样。 当我们解决相同的问题时,我在问使用std :: bind的特定解决方案,该问题仅在其他问题的答案之一中提及,但从未提及。
这是函数声明:
GLFWcharfun glfwSetCharCallback ( GLFWwindow * window,
GLFWcharfun cbfun
)
其中GLFWcharfun定义为typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int)
这里有一个明显的问题,就是您没有机会传递“上下文”对象,该对象会自动将回调映射回InputManager的实例。 因此,您将必须使用唯一可用的键-窗口指针来手动执行映射。
这是一种策略...
#include <map>
#include <mutex>
struct GLFWwindow {};
typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int);
GLFWcharfun glfwSetCharCallback ( GLFWwindow * window,
GLFWcharfun cbfun
);
struct InputManager;
struct WindowToInputManager
{
struct impl
{
void associate(GLFWwindow* window, InputManager* manager)
{
auto lock = std::unique_lock<std::mutex>(mutex_);
mapping_[window] = manager;
}
void disassociate(GLFWwindow* window, InputManager* manager)
{
auto lock = std::unique_lock<std::mutex>(mutex_);
mapping_.erase(window);
}
InputManager* find(GLFWwindow* window) const
{
auto lock = std::unique_lock<std::mutex>(mutex_);
auto i = mapping_.find(window);
if (i == mapping_.end())
return nullptr;
else
return i->second;
}
mutable std::mutex mutex_;
std::map<GLFWwindow*, InputManager*> mapping_;
};
static impl& get_impl() {
static impl i {};
return i;
}
void associate(GLFWwindow* window, InputManager* manager)
{
get_impl().associate(window, manager);
}
void disassociate(GLFWwindow* window, InputManager* manager)
{
get_impl().disassociate(window, manager);
}
InputManager* find(GLFWwindow* window)
{
return get_impl().find(window);
}
};
struct InputManager
{
void init()
{
// how to set up the callback?
// first, associate the window with this input manager
callback_mapper_.associate(window_, this);
// now use a proxy as the callback
glfwSetCharCallback(window_, &InputManager::handleCharCallback);
}
static void handleCharCallback(GLFWwindow * window,
unsigned int ch)
{
// proxy locates the handler
if(auto self = callback_mapper_.find(window))
{
self->charInputCallback(window, ch);
}
}
void charInputCallback(GLFWwindow * window,
int ch)
{
// do something here
}
GLFWwindow* window_;
static WindowToInputManager callback_mapper_;
};
或者,如果您喜欢闭包:
#include <map>
#include <mutex>
struct GLFWwindow {};
typedef void(* GLFWcharfun) (GLFWwindow *, unsigned int);
GLFWcharfun glfwSetCharCallback ( GLFWwindow * window,
GLFWcharfun cbfun
);
struct InputManager;
struct WindowToInputManager
{
using sig_type = void (GLFWwindow *, unsigned int);
using func_type = std::function<sig_type>;
struct impl
{
void associate(GLFWwindow* window, func_type func)
{
auto lock = std::unique_lock<std::mutex>(mutex_);
mapping_[window] = std::move(func);
}
void disassociate(GLFWwindow* window)
{
auto lock = std::unique_lock<std::mutex>(mutex_);
mapping_.erase(window);
}
const func_type* find(GLFWwindow* window) const
{
auto lock = std::unique_lock<std::mutex>(mutex_);
auto i = mapping_.find(window);
if (i == mapping_.end())
return nullptr;
else
return std::addressof(i->second);
}
mutable std::mutex mutex_;
std::map<GLFWwindow*, func_type> mapping_;
};
static impl& get_impl() {
static impl i {};
return i;
}
template<class F>
void associate(GLFWwindow* window, F&& f)
{
get_impl().associate(window, std::forward<F>(f));
glfwSetCharCallback(window, &WindowToInputManager::handleCharCallback);
}
void disassociate(GLFWwindow* window)
{
// call whatever is the reverse of glfwSetCharCallback here
//
// then remove from the map
get_impl().disassociate(window);
}
const func_type* find(GLFWwindow* window)
{
return get_impl().find(window);
}
static void handleCharCallback(GLFWwindow* w, unsigned int ch)
{
auto f = get_impl().find(w);
// note - possible race here if handler calls disasociate. better to return a copy of the function?
if (f) {
(*f)(w, ch);
}
}
};
struct InputManager
{
void init()
{
callback_mapper_.associate(window_, [this](auto* window, int ch) { this->charInputCallback(window, ch); });
}
void charInputCallback(GLFWwindow * window,
int ch)
{
// do something here
}
GLFWwindow* window_;
WindowToInputManager callback_mapper_;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.