将不同的类转换为void*,然后在C 中安全地返回
Converting different classes to void* and back safely in C++
我有一个回调的地图,可以传递信息并在整个代码中执行各种功能,就像C#中的事件一样,但是在C 中。
该地图定义为
std::map<std::string, std::function<void(uint8_t*)>> mCallbacks
它是通过参考所有子程序传递的
然后每个类都将其回调绑定为这样的
mCallbacks["Status_Label"] = std::bind(&MenuHandler::LabelEditCallback, this, std::placeholders::_1);
其中
bool MenuHandler::LabelEditCallback(uint8_t * m_label_data)
{
int text_size = ((int*)m_label_text)[0];
char* v_text = (char*)&m_label_text[1];
}
,每个事件都从类似的不同子程序中调用:
if (mCallbacks.find("Status_Label") != mCallbacks.end())
mCallbacks.at("Status_Label")((uint8_t*)selected_text);
这使得可以轻松地通过程序周围的数据和事件,而无需弄乱对象和参考
您可以看到,这是非常不安全的,并且从UINT8_T指针转换为各种数据格式很容易导致堆栈损坏。
问题是,我没有回调参数的特定结构,其中一些可能正在发送文本数据,其他可能是发送数字。
我的解决方案是定义将在调用事件时将被施放到空白的结构,然后返回回调函数
这样的东西(未经测试(:
struct Label_Callback_Data
{
Label_Callback_Data(std::string v_name, std::string v_text)
{
labelName = v_name;
labelText = v_text;
size_of = sizeof(this);
}
int size_of;
std::string labelName;
std::string labelText;
};
我会这样称呼:
if (mCallbacks.find("Status_Label") != mCallbacks.end())
mCallbacks.at("Status_Label")((uint8_t*)Label_Callback_Data("Status_Label_name", "TEXT"))
但是我将如何在这里恢复?如果我不知道对象的确切大小?
bool MenuHandler::LabelEditCallback(uint8_t * m_label_data)
{
//?? Label_Callback_Data text_size = (Label_Callback_Data*)m_label_text
}
一种解决方案是使用具有固定大小数组的对象,但是必须有一个安全使用的C 11解决方案,也许是使用Dynamic_pointer_cast的东西?
另外,作为一个奖励问题,我如何知道传递给回调功能的对象是否尺寸小于预期?是否可以检查此问题并只需从回调函数中返回一个false,以免程序崩溃?
谢谢,此代码未进行测试,因此我愿意根据响应有逻辑错误。
您通常应该更喜欢使用lambda而不是std::bind()
。
尝试更多类似的东西:
std::map<std::string, std::function<void(void*)>> mCallbacks;
struct Label_Callback_Data
{
std::string labelName;
std::string labelText;
Label_Callback_Data(std::string v_name, std::string v_text)
: labelName(v_name), labelText(v_text) { }
};
...
mCallbacks["Status_Label"] = [this](void *data){ this->LabelEditCallback(data); };
...
auto iter = mCallbacks.find("Status_Label");
if (iter != mCallbacks.end())
{
Label_Callback_Data data("Status_Label_name", "TEXT");
iter->second(&data);
}
...
bool MenuHandler::LabelEditCallback(void *m_label_data)
{
Label_Callback_Data *data = static_cast<Label_Callback_Data*>(m_label_text);
// use data->labelName and data->labelText as needed...
}
另外,您可以将类型铸造移至lambda本身,因此LabelEditCallback()
完全不需要处理void*
:
std::map<std::string, std::function<void(void*)>> mCallbacks;
struct Label_Callback_Data
{
std::string labelName;
std::string labelText;
Label_Callback_Data(std::string v_name, std::string v_text)
: labelName(v_name), labelText(v_text) { }
};
...
mCallbacks["Status_Label"] = [this](void *data){ this->LabelEditCallback(static_cast<Label_Callback_Data*>(data)); };
...
auto iter = mCallbacks.find("Status_Label");
if (iter != mCallbacks.end())
{
Label_Callback_Data data("Status_Label_name", "TEXT");
iter->second(&data);
}
...
bool MenuHandler::LabelEditCallback(Label_Callback_Data *m_label_data)
{
// use m_label_data->labelName and m_label_data->labelText as needed...
}
这就是我做的
...
//The container
std::map<std::string, std::function<void(std::shared_ptr<CallbackData::BlankData>)>> mCallbacks
...
//CALLBACK FUNCTION
bool InputManager::KeyboardCallback(std::shared_ptr<CallbackData::BlankData> callback_data)
{
std::shared_ptr<CallbackData::Keyboard> keyboard_data = std::dynamic_pointer_cast<CallbackData::Keyboard>(callback_data);
if (keyboard_data == nullptr)
return false;
///...
}
...
//CALLBACK EVENT
if (mCallbacks.find("Keyboard") != mCallbacks.end())
{
std::shared_ptr<CallbackData::Keyboard> keyboard_data = std::make_shared<CallbackData::Keyboard>(m_keyboardState);
mCallbacks.at("Keyboard")(std::dynamic_pointer_cast<CallbackData::BlankData>(keyboard_data));
}
...
//Data structure
namespace CallbackData
{
struct BlankData
{
virtual ~BlankData() {};
};
struct Keyboard : public BlankData
{
Keyboard(uint8_t* kb_data)
{
kbData = kb_data;
}
uint8_t* kbData;
};
}
- 从不同线程使用int64的不同字节安全吗
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 虚拟决赛作为安全
- 获取日期异步信号安全吗?如果在信号处理程序中使用,它会导致死锁吗
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 如何将元素添加到数组的线程安全函数?
- C++中的线程安全删除
- 这是我尝试让用户将值输入到数组中.然后将其隐藏为大量的星号
- boost::asio如何生成多个协同程序,然后加入它们
- 通过网络、跨平台传递std::变体是否安全
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- 在std::thread中,joinable()然后join()线程安全吗
- 分离线程然后让它超出范围(并使其仍在运行)是否安全?
- 我可以在中断中写入向量,然后以安全的方式仅在主线程内读取吗?
- 检查指针是否为null,然后在同一if语句中取消引用它,这样安全吗
- 将成员函数指针强制转换为另一个类中的一个然后再返回是否安全
- 将函数放在类中,然后声明"New"是否使其线程安全?
- 将派生对象存储到void*中,然后从中抛出基对象是否不安全
- 将指针强制转换为整数,对该整数自增,然后强制转换回整数是否安全?