如何在 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());
}
我需要在 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());
}