如何混合C ++共享指针和对象引用

时间:2013-09-18 16:12:04

标签: c++ objective-c grand-central-dispatch shared-ptr

我有以下代码在Objective-C函数Datum中使用类work的C ++对象:

void work(const Datum &datum) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Work with datum.
    });
}

使用实际为boost::shared_ptr<Datum>的实例调用此代码,即

boost::shared_ptr<Datum> the_datum(new Datum());
work(*the_datum);

在这种情况下,在the_datum内运行块之前,实例work可能会被释放(对dispatch_async的调用会对datum执行异步操作稍后执行;调用以及函数work立即返回)。这显然会导致灾难。

一种解决方案可能是不传递对work的引用,而是传递boost::shared_ptr<Datum>。但是可能存在优选参考的情况,参见例如this thread。有没有办法保持work的接口(即传递datum作为参考),但仍然阻止在块完成之前重新分配共享指针?

3 个答案:

答案 0 :(得分:3)

将接口保持为work()并将其传递给datum,无法实现此目的。无法使用datum来防止引用计数递减。考虑以下错误程序:

#include <memory>
int main () {
    std::shared_ptr<int> p1(new int);
    int &x = *p1;
    std::shared_ptr<int> p2(&x);
}

此代码因双重释放而崩溃,因为shared_ptr<>控件结构不遵循指向对象的指针,而是跟随shared_ptr<>本身。

您可以做的是更改work()以获取shared_ptr(),但是将更多代码添加到传递给dispatch_async()的块中,以便它可以使用该代码中的引用。由于您要将所有权转移到异步例程,因此应使用unique_ptr<>。我知道关于Objective-C的zilch,所以这种语法可能是错误的:

void work(std::unique_ptr<Datum> &datumptr_ref) {
    __block std::unique_ptr<Datum> datumptr(std::move(datumptr_ref));
    dispatch_async(dispatch_get_main_queue(), ^{
        Datum &datum = *datumptr
        // Work with datum.
    });
}

答案 1 :(得分:1)

您必须自己管理参考文献:

#include <iostream>
#include <memory>

extern "C" {
    typedef struct TagShared Shared;
    Shared* allocate(const std::shared_ptr<int>& ptr) {
        return (Shared*) new std::shared_ptr<int>(ptr);
    }
    void deallocate(Shared* shared) {
        delete (std::shared_ptr<int>*)shared;
    }
 } // extern "C"

int main()
{
    std::shared_ptr<int> s(new int(1));
    Shared* p = allocate(s);
    // Inside Dispatch
        // No C++ but similar defined for TagShared
        std::cout << **(std::shared_ptr<int>*)p << std::endl;
        deallocate(p);
    return 0;
}

答案 2 :(得分:0)

您希望转让所有权,使用std::unique_ptr这样的内容:

void work(std::unique_ptr<Datum> datum) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Work with datum.
    });
}

std::unique_ptr<Datum> the_datum(new Datum());
work(std::move(the_datum));