从lambda返回Eigen :: Map

时间:2016-08-05 10:21:26

标签: c++ lambda eigen eigen3

从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;
}

输出(使用Eigen 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本身。

3 个答案:

答案 0 :(得分:2)

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;

答案 1 :(得分:1)

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

Map<MatrixXd> m(a.data(),2,3);将指向矩阵m中数据的指针作为输入,该数据连续存储在内存中。复制m时,也会复制此指针。

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

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

答案 2 :(得分:-1)

我认为此举将有所帮助

#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;
}

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