Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何通过unsigned long将std::shared_ptr传递给回调?_C++_Shared Ptr - Fatal编程技术网

C++ 如何通过unsigned long将std::shared_ptr传递给回调?

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

我有一个旧的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_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
  • 删除特定的无符号长字符串
(最后两个功能可以组合使用)

这样做的好处是不需要在指针和无符号long之间进行任何不可靠的强制转换,而且(如果返回值基于递增计数器,您可以测试其唯一性),这样可以更容易地发现在同一地址创建、删除一个对象,然后再创建另一个对象的问题

这是一个想法的草图:(特别注意,它不是线程安全的!)

模板类型名
班级商店
{
静态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;
        }
     };