从 C 包装器创建 C++ 对象

Posted

技术标签:

【中文标题】从 C 包装器创建 C++ 对象【英文标题】:Creating C++ objects from C wrappers 【发布时间】:2020-05-13 13:20:54 【问题描述】:

我有一个关于从 C 包装器返回指向 C++ 对象的指针的问题。

这里有两个 C++ 类 AB。我基本上想从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++ 对象的主要内容,如果未能解决你的问题,请参考以下文章

如何为在 C 中使用 C++ 代码创建包装器?

为 C++ 库创建一个 c 包装器

OpenCv c++ 为基本打印垫功能创建一个 C 包装器?

通过在 C++ 接口周围创建 C 包装器,在 FORTRAN 中调用 C++ dll 文件 [关闭]

C++ - 错误:为 OpenCV 的 cv::Scalar::all 创建 C 包装器时出现预期的类型说明符

使用 C++/CLI 包装器将二维数组从 C# 传递到非托管 C++