从 C 包装器创建 C++ 对象
Posted
技术标签:
【中文标题】从 C 包装器创建 C++ 对象【英文标题】:Creating C++ objects from C wrappers 【发布时间】:2020-05-13 13:20:54 【问题描述】:我有一个关于从 C 包装器返回指向 C++ 对象的指针的问题。
这里有两个 C++ 类 A
和 B
。我基本上想从B
创建一个A
的实例。
class A
private:
int a;
public:
explicit A(int a) : a(a) ;
int getA() const
return a;
void setA(int a)
A::a = a;
;
class B
private:
int b;
public:
explicit B(int b) : b(b) ;
int getB() const
return b;
void setB(int b)
B::b = b;
A createA()
return A(getB()); // A will be a complicated object that must be created from B
;
还有 C 包装器
extern "C"
int A_get_a(A *a)
return a->getA();
A *B_getA_1(B *b)
A a = b->createA();
A *a_ptr = &a;
return a_ptr;
void B_getA_2(B *b, A* a_ptr)
A a = b->createA();
a_ptr = &a;
在B_getA_1
中,静态分析器抱怨说
Address of local variable may escape the function.
大概是因为范围界定问题。然而,在B_getA_2
中,当通过以下方式使用该功能时:
int main()
B b(4);
A* a;
B_getA_2(&b, a); // <--
return 0;
;
静态分析器抱怨
Variable 'a' is uninitialized when used here
那么,从B
创建A
实例的好方法是什么?
【问题讨论】:
【参考方案1】:您收到的有关此功能的警告:
A *B_getA_1(B *b)
A a = b->createA();
A *a_ptr = &a;
return a_ptr;
是因为您返回的是局部变量的地址。该变量的生命周期在函数退出时结束,因此返回的指针无效。尝试取消引用该指针会调用 undefined beahavior。
你有这个函数的相关问题:
void B_getA_2(B *b, A* a_ptr)
A a = b->createA();
a_ptr = &a;
在这里,您为 a_ptr
分配了一个值,这是一个参数,因此是函数的本地参数,这意味着它不会影响 main
中的 a
。您需要传递a
的地址并分配给取消引用的指针。但同样,您将导出一个局部变量的地址,该变量的生命周期在函数退出时结束。
您需要更改createA
以返回指向动态分配对象的指针:
A *createA()
return new A(getB());
然后更改您的包装函数以返回:
A *B_getA_1(B *b)
return b->createA();
void B_getA_2(B *b, A **a_ptr)
*a_ptr = b->createA();
并更改调用第二个函数的方式:
B_getA_2(&b, &a);
您还应该为此返回的指针公开一个清理函数:
void free_A(A *a)
delete a;
【讨论】:
【参考方案2】:无论如何,这个:
A a = b->createA();
a_ptr = &a;
return;
...将在堆栈上分配a
,获取其地址,将其返回给调用者,然后销毁a
,因为它是一个局部变量。所以指针无论如何都会指向无效的内存。
您可以返回对象本身(而不是返回一个指向它的指针),或者动态分配内存,将该对象复制到那里并返回一个指向该动态分配区域的指针。
【讨论】:
【参考方案3】:第二个问题:
void B_getA_2(B *b, A* a_ptr)
A a = b->createA();
a_ptr = &a; // this will have no effect, a_ptr is a local variable
你可能想要这个:
void B_getA_2(B *b, A **a_ptr)
A a = b->createA();
*a_ptr = &a;
...
B_getA_2(&b, &a);
但这也是错误的,因为现在您返回一个指向局部变量的指针,请参阅this answer。
【讨论】:
以上是关于从 C 包装器创建 C++ 对象的主要内容,如果未能解决你的问题,请参考以下文章
OpenCv c++ 为基本打印垫功能创建一个 C 包装器?
通过在 C++ 接口周围创建 C 包装器,在 FORTRAN 中调用 C++ dll 文件 [关闭]