如何在 C 中包装 returns 智能指针的 C++ 函数?

How do I wrap a C++ function that returns a smart pointer in C?

我需要在 C 语言的 C++ 库中包装一些 API。我过去曾这样做过,使用指向 class 对象的不透明指针、extern "C" 等 here。然而,我正在处理的这个新库广泛使用了引用计数智能指针。我不确定如何在存在智能指针的情况下进行包装。例如,假设 C++ 库具有以下函数:

SmartPointer<MyClass> foo() {
    SmartPointer<MyClass> ret(new MyClass); // Create smart pointer ret
    ret->DoSomething(); // Do something with ret
    return ret;
}

如何在 C 中包装 foo()?显然,我需要一个不透明指针(如 void* 或空结构指针),我可以在 C 函数中使用它来引用 MyClass 对象。我想到的第一个选项是从 ret 中提取 MyClass 对象,并将其转换为 void*。但是,由于智能指针自动删除,一旦 ret 超出范围,这个 void* 就会变得悬空(如果我错了请纠正我)。

另一种选择是分配一个指向智能指针的指针(比如 retPtr),执行 *retPtr=ret,然后创建一个指向 retPtr 的不透明指针。我认为这个选项可能有用,但这是最好的方法吗?

感谢任何帮助。

您几乎必须 return 一个指向 C 代码的不透明指针。因此,您需要使用 new 分配一个新的智能指针,您可以 return 指向它。

关于您唯一的选择是使用共享指针的集合来使对象保持活动状态。当 C 代码指示它已完成对象时,您从集合中删除共享指针。这允许您 return 您想要的任何类型的标识符到 C 代码——它只是用作在集合中查找对象的句柄。

除了 David Schwartz 的回答之外,您还可以考虑类似于 COM 的 IUnknown 的方法。您可以定义一个包含函数指针的结构(在纯 C 中模拟 C++ 接口),并公开一些方法,如 AddRef 和 Release,以增加和释放引用计数。

调用者获得指向该结构的指针,因此he/she可以使用 AddRef 和 Release 控制返回对象的正确生命周期。

此外,可以在结构中添加其他方法(函数指针)以公开返回对象的其他功能。

This article on COM in plain C 解释的很详细。

注释表明 C 代码需要保存智能指针,但除了将其逐字传递给另一个 C++ 函数外不需要对其执行任何操作。代码可以是:

// Shared  header
#ifdef __cplusplus
extern "C" {
#endif

void * foo_acquire(void);
int  foo_bar(void *);
void foo_release(void *);

#ifdef __cplusplus
}
#endif

// C++ implementation
extern "C" void *foo_acquire()
{
    return new SmartPointer<MyClass>( foo() );
}

extern "C" int foo_bar(void *s)
{
    auto& sp = *static_cast< SmartPointer<MyClass> * >(s);
    return bar(sp);   // bar represents some function expecting the smart pointer
}  

extern "C" void foo_release(void *s)
{
    delete static_cast<SmartPointer<MyClass> *>(s);
}

这使用 SmartPointer 的移动构造函数(如果没有移动构造函数,则使用复制构造函数),智能指针应该支持的操作。

如果要防止 C 代码中的隐式转换,可以使用不透明句柄而不是 void *。 (例如,以 void * 作为成员的结构)。

向 C 代码公开一个结构,而不仅仅是指针。在所述结构中,有指针和一些状态指示器。将行为添加到智能指针,以便它知道该结构。该结构将包含一个指针及其分配对象的状态。因此智能指针的额外行为必须更新结构中分配对象的状态(例如,在智能指针进行释放时将其设置为某个值)。

注释表明 C 代码需要保存一些东西并将 SmartPointer 传递给 C++ API,但除了逐字传递给另一个 C++ 函数外不需要对其做任何事情。

我认为你需要创造一些类似 std::enable_shared_from_this 的想法,比方说 EnableSharedFromThis:

让你的 MyClass 继承自 EnableSharedFromThis:

struct MyClass : public EnableSharedFromThis, public AnotherBaseClass {
//...
};

共享 header:

#ifdef __cplusplus
extern "C" {
#endif

struct MyClass;
MyClass * foo_acquire(void);
int  foo_bar(MyClass *);
void foo_release(MyClass *);

#ifdef __cplusplus
}
#endif

C++ 实现:

List<SmartPointer<MyClass> > listToEnsureLifeTime;
extern "C" MyClass * foo_acquire()
{
    SmartPointer<MyClass> ptr = foo();
    listToEnsureLifeTime.Add(ptr);
    return ptr.get();
}

extern "C" int foo_bar(MyClass *s)
{
    // bar represents some function expecting the smart pointer
    return bar(s->SharedFromThis());
}  

extern "C" void foo_release(MyClass *s)
{
    // I suppose this list can take difference SmartPointer with same
    // inner have the same hash or something like that
    listToEnsureLifeTime.erase(s->SharedFromThis());
}