我有一个本征矩阵要转换为C数组。我可以使用以下示例来复制该问题。

#include <iostream>
#include <Eigen/Core>

int *test()
{
    Eigen::MatrixXi arr = Eigen::MatrixXi::Ones(6,1);
    // just to check
    arr(4)=3;
    arr(5)=19;
    return arr.data();
}

int main()
{
    int *c_arr;
    c_arr = test();

    for (int i=0; i<6;++i)
    {
        std::cout << c_arr[i] << std::endl;
    }

    return 0;
}

输出:
0
0
1
1
3
19

现在,如果我从test函数中打印转换后的C数组值,则这些值是正确的。但是,如果我打印main中的值(如上所示),则前两个索引始终是垃圾。所以我想知道函数调用中发生了什么?我用不同的本征矩阵(类型,大小)进行了尝试,得到的结果相同。

最佳答案

首先,我不是100%熟悉Eigen库(出于好奇而只是下载它来进行查看),并且缺少文档,但是您的问题是一个基本的C问题,可以解决一些方法。

首先,我们将解释代码中提供垃圾值的情况:

int *test()
{
    /* create an auto scoped variable on the stack;
       this variable is only "visible" to this function
       and any references to it or it's underlying data
       outside the scope of this function will result
       in "undefined behaviour" */
    Eigen::MatrixXi arr = Eigen::MatrixXi::Ones(6,1);
    arr(4)=3;
    arr(5)=19;
    /* arr.data() is defined as returning a pointer to the scalar underlying type (or
    a C-style array in other words). Regardless of the type being returned, it is pointer based
    and you are returning a pointer to a location in memory, not the actual data being held in
    the memory. */
    return arr.data();
} /* the variable arr is destroyed here since we left function scope and the return value (the pointer location)
is put in the return register and "program flow" is returned back to the main function where the pointer being
returned now points to "invalid" memory */

int main()
{
    int *c_arr; // create a pointer type that can reference int types
    c_arr = test(); // point it to the result of the test function (see notes above)
    /* c_arr now points to a memory location returned from test, but since the
    arr variable no longer exists here, when you go through and print the values pointed
    to at those memory locations you will get what is at those locations and could be "anything"
    except a valid reference to the original arr variable and it's underlying data. */

    for (int i=0; i<6;++i)
    {
        std::cout << c_arr[i] << std::endl;
    }

    return 0;
}

这就是原因,至于如何解决,有两种方法可以解决您的问题;一种是将返回数组作为变量传递到test函数(例如void test(int*& val))中,然后可以选择在测试函数中为该变量分配新的内存,或者假设用户已经这样做了,并且还必须假设用户会自己清理并调用delete[](因为您正在处理数据数组,所以不只是delete)。

但这有很多警告,需要知道要分配多少空间,并确保完成后要释放空间。我不确定为什么特别需要C样式的数组,但是由于您使用的是C++,因此,如果您使用一些可用的STL和容器函数来帮助您,则可能会更加谨慎,例如:
#include <iostream>
#include <vector>
#include <Eigen/Core>

std::vector<int> test()
{
    Eigen::MatrixXi arr = Eigen::MatrixXi::Ones(6,1);
    arr(4)=3;
    arr(5)=19;
    // we need the size so we know how big of a container to allocate
    std::size_t sz = arr.innerSize() * arr.outerSize();
    std::vector<int> ret(sz);
    // get a temporary C array pointer so we can reference the data
    int* tmp = arr.data();
    // copy from tmp[0] to tmp[sz] and insert the data into the first element of ret
    std::copy(tmp, tmp+sz, ret.begin());
    // return the (copied) data
    return ret;
}

int main()
{
    std::vector<int> c_arr = test();
    // c_arr now points to valid data it holds and can be iterated on
    for (std::size_t i = 0; i < c_arr.size(); ++i) {
        std::cout << c_arr[i] << std::endl;
    }
    // if you need a C-style array from here, you can easily copy the data
    // from the vector to your C-array
    return 0;
}

我研究了使用该类的 cast() 函数,但无法像通过上面的方式复制语法那样使语法减轻痛苦,因为看起来您必须将cast函数调用为另一种Eigen类型,并且然后从那里再次进行转换,但是知道如果需要访问它,可以使用cast函数和其他方法来获取MatrixX类的基础数据。

希望能对您有所帮助。

10-04 15:11
查看更多