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

7

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

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>。但是,在某些情况下,可能更喜欢使用引用,请参见例如此线程。有没有办法保持work接口的方式(即将datum作为引用传递),但仍然防止共享指针在块完成之前被释放?
3个回答

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一窍不通,所以这个语法可能有误:
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

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

#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;
}

您所建议的解决方案中,是否有使用智能指针的特别原因?为什么不使用intrusive_ptr而是手动分配和释放内存?至少这样可以处理在执行分发块时智能指针可能在其他位置的情况。 - user8472
@user8472 当然,使用侵入式指针可能会摆脱分配/释放的问题,但需要引入inc_ref / dec_ref。 - user2249683

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));

3
Objective-C 块会复制捕获的 C++ 对象,因此您不能在这里使用 std::unique_ptr - user1804599
@Paul,你提出的解决方案类似于我上面写的使用boost::shared_ptr<Datum>。我的问题是是否可能保持工作接口,即使用对象引用Datum&而不是智能指针。 - user8472

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接