将C ++对象传递给C例程时的未定义行为

时间:2014-10-10 14:54:25

标签: c++ c numeric

更新

我发现如果我在构造函数中通过引用传递,那么它就解决了A.cpp中的问题!

即。 InfoPass(vector<double> &arg0, vector<double> &arg1...),但原因是什么?

更新

基本上我想从c ++调用一些c代码。

正如c手册中所解释的,为了避免使用gloabal变量,a&#34; void * fdata&#34;用于获取附加信息,如果不是,则指向NULL。

int f(unsigned ndim, unsigned npts, const double *x, void *fdata,
      unsigned fdim, double *fval);

现在我需要打包一些c ++对象并传递给&#34; f&#34;通过这个* fdata参数,我能想到的方法是定义一个类&#34; InfoPass&#34;,并将它传递给c例程。

我的c ++代码段(例如A.cpp和B.cpp,当B没问题时,A无法正常工作):

// Example A.cpp
#include "cubature.h"   // the c library called cubature
#include "extern_cpp_class.hpp" //

class InfoPass
{
    public:
        extern_cpp_class obj1;
        extern_cpp_class obj2;
        extern_cpp_class obj3;
        double arr[3];  

        InfoPass(vector<double>arg0, vector<double>arg1, vector<double>arg2, vector<double>arg3)      
            : obj1{arg0, arg1}, obj2{arg0, arg2}, obj3{arg0, arg3} {}
};

// the declaration of int f() and cubature() below are in the c code
int f(unsigned ndim, const double *x,  void *fdata, unsigned fdim, double *fval);

int main() {
    /*** do something  ***/
    InfoPass cubpass{arg0, arg1, arg2, arg3};  // initialize
    cubature(2, f, &cubpass, 2, xmin, xmax, 1e5, 0, 1e-5, ERROR_PAIRED, OUTPUT, &err);
    /*** process with output ***/
}

int f(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval)
{
    InfoPass *fcubpass=static_cast<InfoPass*>(fdata);
    /*** do things with fcubpass.obj1, .obj2 ...  ***/
}

现在,我可以编译(gcc)并运行示例A,奇怪的是,有未完成的行为,有时它会给出NaN,有时会给出非常疯狂的数字......

但是,如果我采用以下方式(例B,使用指向类的指针),那么使用&#34; new&#34;在f,它工作正常!想知道为什么?因为我更喜欢实例A到B,其中我总是需要&#34; new&#34;财产以后...

// Example B.cpp
class InfoPass
{
    public:
        extern_cpp_class *obj1=NULL;
        extern_cpp_class *obj2=NULL;
        extern_cpp_class *obj3=NULL;
        double arr[3];

        ~InfoPass(){
            delete obj1;
            delete obj2;
            delete obj3;
        }
}

int main() {
    /*** do something  ***/

    InfoPass cubpass;  // declare
    cubpass.obj1 = new extern_cpp_class(arg0,arg1);
    cubpass.obj2 = new extern_cpp_class(arg0,arg2);
    cubpass.obj3 = new extern_cpp_class(arg0,arg3);
    cubature(2, f, &cubpass, 2, xmin, xmax, 1e5, 0, 1e-5, ERROR_PAIRED, OUTPUT, &err);

    /*** process with output ***/
}

int f(unsigned ndim, const double *x, void *fdata, unsigned fdim, double *fval)
{
    InfoPass *fcubpass=static_cast<InfoPass*>(fdata);

    /*** do things with fcubpass->obj1, .obj2 ...  ***/ 
}

3 个答案:

答案 0 :(得分:2)

由于f应该是C代码调用的Callback函数,所以它应该使用c的调用约定。

但是由于你在cpp中声明并定义它,它使用另一个调用约定。 所以参数传递可能会出错。

尝试在extern "C"声明前添加f

但这显然不能令人满意地解释,为什么你的一个例子确实有用。

答案 1 :(得分:2)

这里只是在黑暗中拍摄。

extern_cpp_class个对象的初始化参数是做什么的?如果他们将vector参数作为参考文件并将其存储起来,那么您将遇到原始A.cpp的问题,因为参数是在{{1}之后被销毁的临时副本 - 使引用无效构造函数已完成执行。切换到传递引用可以通过确保cubpass个对象接收extern_cpp_class中创建的vector的引用来解决这个问题,这些main在程序退出之前(可能)保持有效(或至少直到你# 39;重新使用cubpass)。在B.cpp中,构造函数已经获得了对vector的引用,因此没有问题。

答案 2 :(得分:0)

您是否可以更改InfoClass构造函数中的初始化列表以使用括号而不是花括号?

obj1(arg0, arg1), obj2(arg0, arg2), obj3(arg0, arg3)

P.S。我会发布这个评论作为评论,但我还没有声誉。