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

How to mix C++ shared pointers and object references

本文关键字:共享 指针 对象引用 C++ 何混合 混合      更新时间:2023-10-16

我有以下代码,它在 Objective-C 函数work中使用类 Datum 的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>。但在某些情况下,引用是首选的,例如请参阅此线程。有没有办法保留work的接口(即将datum传递作为引用),但仍然防止在块完成之前释放共享指针?

无法

通过让接口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.
    });
}

您必须自己管理引用:

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

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