如何通过unsigned long传递std::shared_ptr给回调函数
How to pass std::shared_ptr to callback through unsigned long?
我有一个旧的c风格库,它使用unsigned long作为用户参数的回调,我想将我的shared_ptr传递给回调,以便引用计数递增。
void callback( unsigned long arg ) {
std::shared_ptr<my_class> ptr = ??? arg ???
}
void starter_function() {
std::shared_ptr<my_class> ptr = std::make_shared<my_class>();
unsigned long arg = ??? ptr ???
// pass to library so it may be used by callback
}
目前我在shared_ptr上使用get(),然后使用c风格的强制转换,但是当start_function超出作用域时,这会产生问题。
创建一个静态存储(可以基于std::map<unsigned long, std::shared_ptr<T>>
)。提供函数给:
- 在store中注册一个共享指针(将其保存在map中,并返回一个唯一的long)。
- 检索特定unsigned long 对应的
- 删除特定的unsigned long
shared_ptr
。(后两个函数可以合并)。
这样做的好处是不需要在指针和unsigned long之间进行任何危险的强制转换,而且(如果返回值基于一个递增计数器,您可以测试其唯一性),可以更容易地发现一个对象被创建、删除,然后在同一地址创建另一个对象的问题。
这是一个想法的草图:(特别注意,它不是线程安全的!)
template typename<T>
class Store
{
static std::map<unsigned long, std::shared_ptr<T>> store;
unsigned long h;
bool contains(unsigned long i)
{
return store.find(i) != store.end();
}
public:
unsigned long save(const std::shared_ptr& ptr)
{
if (store.size() >= std::numeric_limits<unsigned long>::max())
{
// Handle error. Only possible if 64 bit program with
// 32 bit unsigned long.
}
// find an unused handle.
do
{
++h;
}
while(contains(h)); // Not a good approach if there are main long-lived objects, and h might wrap.
// Store and return handle.
store[h] = ptr;
return h;
}
std::shared_ptr<T> retrieve(unsigned long handle)
{
if (!contains(handle))
{
// handle error
}
const auto result = store[handle];
store.erase(handle);
return result;
}
};
遗憾的是,这个问题没有"goto"解决方案。我有过几次这样的情况,并根据具体情况以不同的方式解决了这个问题。
一个"简单"的解决方案是(如果你有一些类)将指针作为类成员存储在容器中,以确保它们保持活动状态。然后在函数内部使用原始指针。但是你必须确保当你的对象被销毁时回调函数不会被调用(所以将回调函数与对象一起存储)。只有当不从容器中删除任何对象时,这才能顺利地工作。
对于线程,通过引用传递共享的ptr,然后复制它
{
auto sP = make_shared<...>(...);
thread_start(&sp);
wait_for_thread_init();
}
void thread_start(std::shared_ptr<...>* ref )
//or unsigned long but you can cast this to a shared_ptr<...>* later.
{
std::shared_ptr otherPointer = *ref; //here your ref count gets increased
send_init_complete();
//never use ref from here on. only otherPointer.
}
但是c++ 11有一个自己的线程库可以更好地处理这个问题,所以当你使用线程时应该使用它。
取决于你所处的环境,你必须要有创意。最后,当您没有实际的解决方案时,您需要使用原始指针。只需添加足够的注释,说明回调应该删除这些对象等。
您有两个基本选项。这两个选项都假设在您的平台上,unsigned long
足够大以容纳指针:
-
将指向
std::shared_ptr
的指针转换为unsigned long
,并传递它 -
使用
get()
来检索底层指针,并且只传递它
对于第二个选项,假设你的回调不需要构造另一个shared_ptr
;否则你需要使用enable_shared_from_this
。
另外,这两个选项都假设当回调被调用时,shared_ptr
和底层对象将保持在作用域中。如果不是:
- 使用
new
复制shared_ptr
你将需要delete
后,它不再需要,回调不再使用。
如果在你的平台上,unsigned long
不够大,不能容纳一个指针,它就会变得笨拙。最干净的解决方案是保留一个std::map<unsigned long, std::shared_ptr<...>>
,并为每个shared_ptr
分配一个唯一的unsigned long
值的计数器,将shared_ptr
插入映射,并将映射的键传递给回调。
- 架构决策:返回std::future还是提供回调
- 正在为Xtensa simcall函数编写回调函数
- 如何在C++中使用非静态成员函数作为回调函数
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 用于在回调中调用解析器的设计模式
- 如何使用C++对象的成员函数作为 C 样式回调?
- Java从C++回调到C++回调
- 如何将成员函数作为回调参数传递给需要"typedef-ed"自由函数指针的函数?
- 从不同的 cpp 调用回调函数会导致bad_function_call
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 不带轮询的 SDL2 事件回调
- C++存储带有可变参数的回调
- 如何使用 Node-addon-API 实现 node-nan 回调
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 访问类C++ C 样式回调
- 处理类内的回调时,必须调用对非静态成员函数的引用
- 如果 C 函数仍然可以间接执行(通过回调函数),那么将它声明为静态函数是否是一种不好的做法?
- 在C++中实现回调
- C++ 事件管理器的回调,使用 std::function 和 std:bind 以及派生类作为参数