我有一个旧的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超出范围时会产生问题。
答案 0 :(得分:9)
创建一个静态存储(可以基于std::map<unsigned long, std::shared_ptr<T>>
)。提供以下功能:
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;
}
};
答案 1 :(得分:1)
可悲的是,没有&#34;转到&#34;这个问题的解决方案。我有几次,并根据情况不同地解决这个问题。
&#34; easy&#34;解决方案是(如果你有一些类)将指针存储在容器中作为类成员,因此确保它们保持活着状态。然后在函数内部使用原始指针。您必须确保在销毁对象时不会调用您的回调(因此将回调与对象一起存储)。只有当您不从容器中移除任何对象时,这才能顺利运行。添加很好。
使用线程,您可以通过引用传递共享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有一个自己的线程库可以更好地处理这个问题,因此你应该在使用线程时使用它。
根据您的环境,您必须在此处发挥创意。最后,当你没有实际的解决方案时,你需要使用原始指针。只需添加足够的内容来评论回调应该删除那些对象等。
答案 2 :(得分:1)
您有两个基本选项。这两个选项都假设在您的平台上,unsigned long
足以容纳指针:
将指针转换为std::shared_ptr
至unsigned long
,并将其传递。
使用get()
检索基础指针,然后传递它。
对于第二个选项,假设您的回调不需要构建另一个shared_ptr
;否则你需要使用enable_shared_from_this
。
此外,这两个选项都假定在调用回调时shared_ptr
和底层对象将保留在作用域中。如果不是:
shared_ptr
制作new
的副本。在不再需要后,您需要delete
,并且不再使用回调。如果在您的平台上unsigned long
不足以容纳指针,它会变得更加笨拙。最干净的解决方案是保持std::map<unsigned long, std::shared_ptr<...>>
左右,以及为每个unsigned long
分配唯一shared_ptr
值的计数器,将shared_ptr
插入地图,然后通过映射回调的关键。