从lambda返回一个Eigen::Map



从lambda函数返回Eigen::Map会给出错误的输出:

#include<iostream>
#include<eigen3/Eigen/Dense>
using namespace std;
using namespace Eigen;
int main(){
    auto doIt = [](){
        MatrixXd a = MatrixXd::Random(2,3);
        Map<MatrixXd> m(a.data(),2,3);
        cout << "a:n" << a << endl;
        cout << "m:n" << m << endl;
        return m;
    };
    MatrixXd o(2,3);
    o = doIt();
    cout << "o:n" << o << endl;
   return 0;
}

输出(使用特征3.2.9-1):

a:
 0.680375  0.566198  0.823295
-0.211234   0.59688 -0.604897
m:
 0.680375  0.566198  0.823295
-0.211234   0.59688 -0.604897
o:
5.15038e-317     0.566198     0.823295
-0.211234      0.59688    -0.604897

如果使用clang++ -std=c++11 -fsanitize=address编译,我将进一步获得堆使用后自由错误。(clang版本3.7.1)

如果我将lambda转换为返回Eigen::MatrixXd的函数,它就会工作——可能是因为额外的复制。有没有办法让它在lambda中工作,而不使用额外的MatrixXd并将映射的内容复制到它?

(在我的用例中,lambda只能访问Map m,而不能访问MatrixXd a本身)。

Map不拥有数据,它只包装现有数据。如果数据被释放或修改,Map将不知道。这正是这里发生的事情:

auto doIt = [](){
    // Here MatrixXd dynamically allocates memory for its content
    MatrixXd a = MatrixXd::Random(2,3);
    // Now you save pointer to this allocated memory
    Map<MatrixXd> m(a.data(),2,3);
    cout << "a:n" << a << endl;
    cout << "m:n" << m << endl;
    return m;
    // When leaving the scope via return or simple end of block
    // all local variables will be destroyed.
    // When destorying, Matrix will also free
    // what it owns thus Map will point to invalid memory
};

所以基本上你是在访问一个释放的内存。您需要返回拥有资源的对象:

auto doIt = [](){
    return MatrixXd::Random(2,3);
};
auto a = doIt();
Map<MatrixXd> m(a.data(),2,3);
cout << "a:n" << a << endl;
cout << "m:n" << m << endl;
MatrixXd o(2,3);
cout << "o:n" << o << endl;

我只是在详细阐述@GuillaumeRacicot的评论,他已经在评论中给出了答案。

CCD_ 8将指向连续存储在存储器中的矩阵CCD_ 9中的数据的指针作为输入。复制m时,也会复制此指针。

现在,矩阵a仅在doIt()的范围内定义,并且在堆栈上分配。一旦doIt()完成,a就会被销毁,并且指向它的任何指针都将变为无效。

这正是这里发生的事情:当o试图访问数据时,它已经不见了,同时内存中的区域可能会被用来做一些不同的事情。这就是为什么你看到一些元素仍然是一样的,但其他元素已经改变了。

我认为此举将有助于

#include<iostream>
#include<eigen3/Eigen/Dense>
using namespace std;
using namespace Eigen;
int main(){
    auto&& doIt = [](){
        MatrixXd a = MatrixXd::Random(2,3);
        Map<MatrixXd> m(a.data(),2,3);
        cout << "a:n" << a << endl;
        cout << "m:n" << m << endl;
        return std::move(m);
    };
    MatrixXd o(2,3);
    o = doIt();
    cout << "o:n" << o << endl;
   return 0;
}

无法测试它,因为我没有本地特征

最新更新