通过使用void*的C接口传递shared_ptr
Passing a shared_ptr through a C interface that takes void *
我有一个C++项目,它使用SDL,特别是SDLEvents。我想将事件系统用于传入的网络消息,就像它用于UI事件一样。我可以定义一个新的事件类型并附加一些任意的数据(参见本示例)。如果我使用普通指针,我会这样做:
Uint32 message_event_type = SDL_RegisterEvents(1);
/* In the main event loop */
while (SDL_Poll(&evt)) {
if (evt.type == message_event_type) {
Message *msg = evt.user.data1;
handle_message(msg);
}
}
/* Networking code, possibly in another thread */
Message *msg = read_message_from_network();
SDL_Event evt;
evt.type = message_event_type;
evt.user.data1 = msg;
SDL_PostEvent(evt);
相反,到目前为止,我一直在使用shared_ptr<Message>
。消息在构造后是只读对象,在处理时可能会在很多地方使用,所以我想对它们使用shared_ptr。
我想在网络端和事件处理端对消息使用shared_ptr。如果我这样做:
// in networking code:
shared_ptr<Message> msg = ...
evt.user.data1 = msg.get();
// later, in event handling:
shared_ptr<Message> msg(evt.user.data1);
然后有两个独立的shared_ptr,其中一个可以在其中一个仍在使用Message对象时删除它。我需要以某种方式通过SDL_UserEvent结构传递shared_ptr,该结构只有两个void *
和int字段。
附加注意SDL_PostEvent
会立即返回;事件本身被放入队列中。在消息的shared_ptr在网络代码中超出范围之后,处理程序可能会从队列中弹出该事件。因此,我无法传递要从中复制的本地shared_ptr的地址。到复制发生时,它可能不再有效。
有没有人遇到过类似的问题,知道一个好的解决方案?
用new分配一个指向共享ptr的指针。这会调用构造函数(增加引用计数),但不会调用相应的析构函数,因此shared_ptr永远不会析构函数的共享内存。
然后在相应的处理程序中,只需在复制shared_ptr后销毁对象,使其引用计数恢复正常。
这与通过消息队列传递任何其他非基元类型的方式相同。
typedef shared_ptr<Message> MessagePtr;
Uint32 message_event_type = SDL_RegisterEvents(1);
/* In the main event loop */
while (SDL_Poll(&evt)) {
if (evt.type == message_event_type) {
// Might need to cast data1 to (shared_ptr<Message> *)
unique_ptr<MessagePtr> data (evt.user.data1);
MessagePtr msg = *data;
handle_message(msg);
}
}
/* Networking code, possibly in another thread */
MessagePtr msg = read_message_from_network();
SDL_Event evt;
evt.type = message_event_type;
evt.user.data1 = new MessagePtr (msg);
SDL_PostEvent(evt);
一旦构建,消息就是只读对象
我只想指出,这是好的,甚至是多线程安全所必需的。您可能想要使用shared_ptr<const Message>
似乎是使用std::enable_shared_from_this
的理想场所
struct Message: std::enable_shared_from_this<Message>
{
…
};
evt.user.data1 = msg.get();
// this msg uses the same refcount as msg above
shared_ptr<Message> msg = evt.user.data1.shared_from_this();
我想到了另一种潜在的技术:使用placement new将shared_ptr
存储在与C结构相同的空间中:
SDL_Event evt;
evt.type = event_type;
// create new shared_ptr, in the same memory as evt.user.code
new (&evt.user.code) shared_ptr<Message>(msg);
SDL_PushEvent(&evt);
SDL然后将事件复制为C对象,直到稍后的代码从事件中提取消息:
shared_ptr<Message> get_message(SDL_Event& evt) {
// copy shared_ptr out of evt
shared_ptr<Message> msg = *reinterpret_cast<shared_ptr<Message> *>(&evt.user.code);
// destroy shared_ptr inside the event struct
(reinterpret_cast<shared_ptr<Message> *>(&evt.user.code))->~shared_ptr();
return msg;
}
事件结构中有几个字段应该有足够的空间用于shared_ptr(请参阅https://github.com/spurious/SDL-mirror/blob/master/include/SDL_events.h#L485)。
我知道这有点让人生气。我希望能对这项技术进行一些理智的检查。
- C++核心准则 C35 对于接口类"A base class destructor should be either public and virtual, or protected and nonv
- Visual C++GC接口如何启用它以及要包含哪个库
- Windows.h与GLFW.h的接口
- 当字段可以为null时,如何使用C++接口在Avro中写入数据
- 提供与TMP和SFINAE的通用接口
- 为重写std::exception的库生成swig接口时出错
- 内联如何影响模块接口中的成员函数
- COM 接口 c# 封送数组数组
- 如何在 SCIP C++ 接口中获取 MILP 约束矩阵中的系数值
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 如何绑定 C++ gRPC 客户端的网络接口
- 模板化接口 - 创建一个泛型模板类以返回任何容器
- 如何从实现接口的模板化类实例访问结构
- 带有进度表的 curl 多接口程序
- 设计帮助 - 为不同类型的消息处理通用接口的设计模式
- 我可以在具有一个标头和一个接口的 cpp 文件中有多个嵌入吗?
- 类接口,可以创建N个方法
- 类具有相同的接口,但参数的类型不同
- 如何与 Cheerp/js 中的 extern 变量接口?
- 如何使用现代 CMake 安装捆绑的接口依赖项?