C++ 如何通过unsigned long将std::shared_ptr传递给回调?
我有一个旧的C风格库,它使用带有unsigned long的callback作为用户参数,我想将我的shared_ptr传递给callback,以便增加引用计数C++ 如何通过unsigned long将std::shared_ptr传递给回调?,c++,shared-ptr,C++,Shared Ptr,我有一个旧的C风格库,它使用带有unsigned long的callback作为用户参数,我想将我的shared_ptr传递给callback,以便增加引用计数 void callback( unsigned long arg ) { std::shared_ptr<my_class> ptr = ??? arg ??? } void starter_function() { std::shared_ptr<my_class> ptr = std::make_s
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
}
void回调(无符号长参数){
std::shared_ptr ptr=???arg???
}
void start_函数(){
std::shared_ptr ptr=std::make_shared();
无符号长参数=???ptr???
//传递到库,以便回调可以使用它
}
目前,我在shared_ptr上使用get(),然后使用C样式的强制转换,但这会在start_函数超出范围时产生问题。遗憾的是,对于这个问题没有“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.
}
{
自动sP=使_共享(…);
线程启动(&sp);
等待线程初始化();
}
无效线程\u开始(标准::共享\u ptr*ref)
//或unsigned long,但您可以稍后将其强制转换为共享的\u ptr*。
{
std::shared\u ptr otherPointer=*ref;//这里您的ref计数增加
发送初始化完成();
//从此不再使用ref。只使用otherPointer。
}
但是C++11有自己的线程库,可以更好地处理这个问题,所以在使用线程时应该使用它
取决于你的环境,你必须在这里发挥创造力。最后,当您没有实际的解决方案时,您需要使用原始指针。只需添加足够的注释,回调就可以删除这些对象等。创建一个静态存储(可以基于
std::map
)。提供以下功能:
- 在存储中注册共享指针(这会将其保存在映射中,并返回唯一的long)李>
- 检索与特定无符号长字符串对应的
共享\u ptr
- 删除特定的无符号长字符串
模板类型名
班级商店
{
静态std::地图存储;
无符号长h;
布尔包含(无符号长i)
{
return store.find(i)!=store.end();
}
公众:
无符号长保存(常量std::shared_ptr&ptr)
{
如果(store.size()>=std::numeric_limits::max())
{
//处理错误。仅当64位程序具有
//32位无符号长。
}
//查找未使用的句柄。
做
{
++h;
}
while(contains(h));//如果存在主要的长寿命对象,则这不是一个好方法,而h可能会换行。
//存储和返回手柄。
存储[h]=ptr;
返回h;
}
std::shared_ptr retrieve(无符号长句柄)
{
如果(!包含(句柄))
{
//处理错误
}
常量自动结果=存储[句柄];
存储。擦除(句柄);
返回结果;
}
};
您有两个基本选项。这两个选项都假设在您的平台上,无符号long
足够大,可以容纳指针:
std::shared_ptr
的指针转换为unsigned long
,并传递它get()
shared_ptr
;否则,您需要使用从\u this
启用\u shared\u
此外,这两个选项都假定调用回调时,共享的\u ptr
和底层对象将保持在范围内。如果没有:
new
复制共享的\u ptr
。在不再需要它并且不再使用回调后,您将需要删除它如果在您的平台上,一个
无符号长的不够大,无法容纳指针,那么它会变得更笨拙。最干净的解决方案是保留一个std::map
,以及一个计数器,为每个shared\u ptr
分配一个唯一的unsigned long
值,将shared\u ptr
插入映射,并将映射的键传递给回调。这也是一个很好的解决方案。当您在执行过程中依赖RAII时,它会有一些问题,因为您要么必须手动删除对象,要么只有在二进制结束时它们才会被销毁。但是如果你不需要在不需要的时候释放内存,那就很好了。不,如果你可以从存储中删除共享的ptr(如示例代码中所示),那么只有在回调完成之前,共享ptr才有效。啊,是的。但是,当您两次使用相同的“id”时,您会遇到问题。例如,注册一个共享指针一次,并为2个回调提供“id”。我的意思是,您可以“捕获”错误,但这只是为了让用户意识到以避免这种情况。就像我说的那样。很好的解决方案。:)当我再次遇到这个问题时,请记住这一点。最好的解决方案可能是为每个回调提供自己的id。否则,您需要将“retrieve”和“remove from store”函数分开(并调用后一个ca)
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;
}
};