【Eigen教程11】Eigen::Map详解——零拷贝映射外部数据与存储顺序解析一、Eigen::Map简介和构造函数1、构造函数形式一默认列优先2、构造函数形式二2.1、重要设置 Options需要设置MatrixType为原生的模式二、基本用法1、Eigen映射到Eigen2、数组映射到Eigen3、stl容器映射到Eigen4、 Eigen::Matrix 转换为 std::vector三、注意事项1、为何说它是映射2、明确指定存储顺序RowMajor/ColMajor无效原创作者郑同学的笔记原文链接https://zhengjunxue.blog.csdn.net/article/details/149217351一、Eigen::Map简介和构造函数Eigen::Map 是 Eigen 库中的关键类。它允许将现有的内存块如 C/C 数组、std::vector 或第三方库的数据直接映射为 Eigen 的矩阵或向量对象无需复制数据。核心优势高效避免大型数据拷贝开销灵活无缝集成外部数据源原位计算直接修改原始内存1、构造函数形式一默认列优先MapMatrixType(PointerType data,Index rows,Index cols);参数PointerType data指向数据的指针与前述一样指向存储数据的内存区域。Index rows矩阵的行数。Index cols矩阵的列数。2、构造函数形式二Eigen::MapMatrixType,Options,StrideType(data_pointer,rows,cols);构造函数和参数说明2.1、MatrixType (映射的目标矩阵类型):MatrixType 是你映射到的目标矩阵类型。例如 Eigen::Matrix 。例如如果你希望映射一个 int 类型的矩阵MatrixType 会是 Eigen::Matrixint, -1, -1这里的 -1 表示动态大小。2.2、Options (选项标志): 是一个可选参数,矩阵存储选项控制数据存储顺序如按行主序或列主序。默认是按列主序存储。作用: 控制内存存储顺序列优先或行优先。可选值:Eigen::ColMajor: 列优先默认同 MATLAB。Eigen::RowMajor: 行优先同 C 数组。这个参数对 Eigen::Map 的行为有重要影响特别是当数据存储顺序不同时。2.3、StrideType (步长类型):StrideType 用来控制行和列的步长即内存中元素间的跳跃距离。它通常是 Eigen::Stride 类型。这个参数允许你在映射过程中指定自定义的行和列步长以便适应特定的内存布局。Eigen::Stride0, 1 是最常用的配置表示按行主序存储每行的元素在内存中是连续的。第一个 0 表示列步长由 Eigen 自动计算。第二个 1 表示行步长为 1意味着每一行是连续的。默认: Stride0,0 表示连续内存自动计算跨步。示例映射一个每列间隔为 4 的 3x3 子矩阵doubledata[12];// 原始数组Eigen::MapEigen::Matrix3d,0,Eigen::Stride4,1submap(data);2.1、重要设置 Options需要设置MatrixType为原生的模式比如矩阵类型是 Eigen::MatrixXf它始终是列优先所有可以写为usingRowMatrixXfEigen::Matrixfloat,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor;Eigen::MapRowMatrixXfmat3(data[0],2,3);二、基本用法1、Eigen映射到Eigen1.1. 矩阵映射到不同维度的矩阵Matrix——Matrix#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){MatrixXimat(2,3);mat1,2,3,4,5,6;coutmat\nmat;cout\n------------------------\n;Eigen::MapEigen::MatrixXimat2(mat.data(),3,2);coutmat2\nmat2;return0;}输出mat123456------------------------mat21543261.2. 矩阵映射到向量Matrix——VectorXi#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){MatrixXimat(2,3);mat1,2,3,4,5,6;coutmat\nmat;cout\n------------------------\n;Eigen::MapEigen::VectorXimat2(mat.data(),6);coutmat2\nmat2;return0;}输出mat123456------------------------mat21425362、数组映射到Eigen2.1、一维数组映射到Eigen向量#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){doublearr[6]{1,2,3,4,5,6};// 映射为 Eigen 向量Eigen::MapEigen::VectorXdvec(arr,6);coutvec;// 直接操作原始数组vec*2;// arr 变为 [2, 4, 6, 8, 10, 12]return0;}2.1、二维数组映射到Eigen向量二维数组内存是连续的#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){floatdata[2][3]{{1.0f,2.0f,3.0f},{4.0f,5.0f,6.0f}};// 映射为 2x3 矩阵 (列优先行优先无效)Eigen::MapEigen::MatrixXfmat(data[0][0],2,3);coutmat;cout\n-----------------\n;// 映射的矩阵类型是 Eigen::MatrixXf它始终是列优先Eigen::MapEigen::MatrixXf,Eigen::RowMajormat1(data[0][0],2,3);cout\nmat1 is row-major: (mat1.IsRowMajor?true:false\n)endl;coutmat1;cout\n-----------------\n;usingRowMatrixXfEigen::Matrixfloat,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor;Eigen::MapRowMatrixXfmat3(data[0],2,3);coutmat3;// 使用 Eigen 函数//Eigen::MatrixXf mat2 mat.transpose(); // 转置不修改原始数据return0;}输出135246----------------- mat1 is row-major:false135246-----------------123456为什么 IsRowMajor 返回 false因为映射的矩阵类型是 Eigen::MatrixXf它始终是列优先3、stl容器映射到Eigen3.1、一维std::vector映射为Eigen::VectorXf#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){std::vectorfloatvec(10,1.23f);// 10个元素初始化为1.23// 映射 std::vectorEigen::MapEigen::VectorXfvec_map(vec.data(),vec.size());coutvec_map;return0;}3.2、二维std::vector映射为Eigen::VectorXf通过 Eigen::Map 将 std::vector 映射为 Eigen::Matrix。假设你的 std::vector 是一个二维数组你可以利用 std::vector 的底层内存结构即连续的内存块来创建一个映射。扁平化 std::vector首先我们将二维 std::vector 扁平化为一维 std::vector因为 Eigen::Map 只支持一维数组作为输入。#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){// 创建一个 2x3 的 std::vectorvectorvectorfloatvec{{1.0f,2.0f,3.0f},{4.0f,5.0f,6.0f}};// 将二维 std::vector 扁平化为一维数组vectorfloatflat_data;for(constautorow:vec){flat_data.insert(flat_data.end(),row.begin(),row.end());}// 使用 Eigen::Map 映射为 Eigen 矩阵Eigen::MapEigen::MatrixXfmat(flat_data.data(),2,3);// 2行3列coutMapped Eigen Matrix:\n;coutmatendl;return0;}输出Mapped Eigen Matrix:1352464、 Eigen::Matrix 转换为 std::vector要将 Eigen::Matrix 转换为 std::vector我们可以通过访问 Eigen::Matrix 的数据指针并将其复制到 std::vector 中。下面是一个示例#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){// 创建一个 2x3 的 Eigen 矩阵MatrixXfmat(2,3);mat1.0f,2.0f,3.0f,4.0f,5.0f,6.0f;coutOriginal Eigen Matrix:\n;coutmatendl;cout--------------------------\n;// 将 Eigen 矩阵转换为 std::vectorstd::vectorfloatvec(mat.data(),mat.data()mat.size());// 输出转换后的 std::vectorcout\nConverted std::vector:\n;for(floatv:vec){coutv ;}coutendl;cout--------------------------\n;std::vectorfloatvec2;vec2.resize(mat.size());MapVectorXf(vec2.data(),mat.size())MapVectorXf(mat.data(),mat.size());cout\nConverted std::vector:\n;for(floatv:vec2){coutv ;}coutendl;return0;}输出Original Eigen Matrix:123456-------------------------- Converted std::vector:142536-------------------------- Converted std::vector:142536三、注意事项1、为何说它是映射Eigen::Map 并没有复制数据它只是引用了原始数据的内存位置#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){// 创建 2x3 的 MatrixXi 矩阵MatrixXimat(2,3);mat1,2,3,4,5,6;coutmat\nmat;cout\n------------------------\n;// 映射到 mat2Eigen::MapEigen::MatrixXimat2(mat.data(),3,2);// 确保维度与 mat 匹配coutmat2\nmat2;// 清理原矩阵数据cout\n----------清理 mat 数据--------------\n;mat.resize(1,1);// 原矩阵数据清理coutmat\nmatendl;// 映射矩阵 mat2 无效尝试输出会导致错误coutmat2\nmat2endl;// 这时访问 mat2 将导致未定义行为return0;}输出mat123456------------------------mat2154326----------清理 mat 数据--------------mat-842150451mat2-572662307-572662307-572662307-572662307-572662307-572662307Eigen::Map 只是对现有数据的一个视图。当调用 mat.resize(1, 1) 时原始矩阵 mat 的数据被清理并重新分配了这导致映射 mat2 所依赖的数据也消失了。这是因为 Eigen::Map 并没有复制数据它只是引用了原始数据的内存位置。解决方案为了确保数据不丢失映射的矩阵应该在原始矩阵的生命周期内保持有效或者我们可以在清理数据之前将其复制到另一个持久存储结构中。2、明确指定存储顺序RowMajor/ColMajor无效存储顺序问题:MatrixXf 本质是 Matrixfloat, Dynamic, Dynamic, ColMajor添加 Eigen::RowMajor 作为第二个模板参数不会改变存储顺序正确方法是定义新的矩阵类型如 RowMatrixXf#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){floatdata[2][3]{{1.0f,2.0f,3.0f},{4.0f,5.0f,6.0f}};// 1. 映射为列优先矩阵默认Eigen::MapEigen::MatrixXfmat(data[0][0],2,3);cout列优先映射 (默认):\nmatendl;cout存储顺序: (mat.IsRowMajor?行优先:列优先)endl;cout\n-----------------\n;// 2. 错误尝试映射为行优先实际无效// 注意MatrixXf 固定为列优先RowMajor 被误解为对齐选项Eigen::MapEigen::MatrixXf,Eigen::RowMajormat1(data[0][0],2,3);cout无效行优先尝试:\n;coutmat1 is row-major: (mat1.IsRowMajor?true:false)endl;coutmat1endl;cout\n-----------------\n;// 3. 正确映射为行优先矩阵usingRowMatrixXfEigen::Matrixfloat,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor;Eigen::MapRowMatrixXfmat3(data[0],2,3);// 注意这里用 data[0]cout正确行优先映射:\nmat3endl;cout存储顺序: (mat3.IsRowMajor?行优先:列优先)endl;return0;}列优先映射(默认):135246存储顺序:列优先-----------------无效行优先尝试:mat1 is row-major:false135246-----------------正确行优先映射:123456存储顺序:行优先data[0][0] vs data[0]:两者完全等价都指向第一个元素 data[0][0] 的地址data[0] 是 float[3] 类型但会自动退化为 float*
【Eigen教程11】Eigen::Map详解——零拷贝映射外部数据与存储顺序解析
【Eigen教程11】Eigen::Map详解——零拷贝映射外部数据与存储顺序解析一、Eigen::Map简介和构造函数1、构造函数形式一默认列优先2、构造函数形式二2.1、重要设置 Options需要设置MatrixType为原生的模式二、基本用法1、Eigen映射到Eigen2、数组映射到Eigen3、stl容器映射到Eigen4、 Eigen::Matrix 转换为 std::vector三、注意事项1、为何说它是映射2、明确指定存储顺序RowMajor/ColMajor无效原创作者郑同学的笔记原文链接https://zhengjunxue.blog.csdn.net/article/details/149217351一、Eigen::Map简介和构造函数Eigen::Map 是 Eigen 库中的关键类。它允许将现有的内存块如 C/C 数组、std::vector 或第三方库的数据直接映射为 Eigen 的矩阵或向量对象无需复制数据。核心优势高效避免大型数据拷贝开销灵活无缝集成外部数据源原位计算直接修改原始内存1、构造函数形式一默认列优先MapMatrixType(PointerType data,Index rows,Index cols);参数PointerType data指向数据的指针与前述一样指向存储数据的内存区域。Index rows矩阵的行数。Index cols矩阵的列数。2、构造函数形式二Eigen::MapMatrixType,Options,StrideType(data_pointer,rows,cols);构造函数和参数说明2.1、MatrixType (映射的目标矩阵类型):MatrixType 是你映射到的目标矩阵类型。例如 Eigen::Matrix 。例如如果你希望映射一个 int 类型的矩阵MatrixType 会是 Eigen::Matrixint, -1, -1这里的 -1 表示动态大小。2.2、Options (选项标志): 是一个可选参数,矩阵存储选项控制数据存储顺序如按行主序或列主序。默认是按列主序存储。作用: 控制内存存储顺序列优先或行优先。可选值:Eigen::ColMajor: 列优先默认同 MATLAB。Eigen::RowMajor: 行优先同 C 数组。这个参数对 Eigen::Map 的行为有重要影响特别是当数据存储顺序不同时。2.3、StrideType (步长类型):StrideType 用来控制行和列的步长即内存中元素间的跳跃距离。它通常是 Eigen::Stride 类型。这个参数允许你在映射过程中指定自定义的行和列步长以便适应特定的内存布局。Eigen::Stride0, 1 是最常用的配置表示按行主序存储每行的元素在内存中是连续的。第一个 0 表示列步长由 Eigen 自动计算。第二个 1 表示行步长为 1意味着每一行是连续的。默认: Stride0,0 表示连续内存自动计算跨步。示例映射一个每列间隔为 4 的 3x3 子矩阵doubledata[12];// 原始数组Eigen::MapEigen::Matrix3d,0,Eigen::Stride4,1submap(data);2.1、重要设置 Options需要设置MatrixType为原生的模式比如矩阵类型是 Eigen::MatrixXf它始终是列优先所有可以写为usingRowMatrixXfEigen::Matrixfloat,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor;Eigen::MapRowMatrixXfmat3(data[0],2,3);二、基本用法1、Eigen映射到Eigen1.1. 矩阵映射到不同维度的矩阵Matrix——Matrix#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){MatrixXimat(2,3);mat1,2,3,4,5,6;coutmat\nmat;cout\n------------------------\n;Eigen::MapEigen::MatrixXimat2(mat.data(),3,2);coutmat2\nmat2;return0;}输出mat123456------------------------mat21543261.2. 矩阵映射到向量Matrix——VectorXi#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){MatrixXimat(2,3);mat1,2,3,4,5,6;coutmat\nmat;cout\n------------------------\n;Eigen::MapEigen::VectorXimat2(mat.data(),6);coutmat2\nmat2;return0;}输出mat123456------------------------mat21425362、数组映射到Eigen2.1、一维数组映射到Eigen向量#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){doublearr[6]{1,2,3,4,5,6};// 映射为 Eigen 向量Eigen::MapEigen::VectorXdvec(arr,6);coutvec;// 直接操作原始数组vec*2;// arr 变为 [2, 4, 6, 8, 10, 12]return0;}2.1、二维数组映射到Eigen向量二维数组内存是连续的#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){floatdata[2][3]{{1.0f,2.0f,3.0f},{4.0f,5.0f,6.0f}};// 映射为 2x3 矩阵 (列优先行优先无效)Eigen::MapEigen::MatrixXfmat(data[0][0],2,3);coutmat;cout\n-----------------\n;// 映射的矩阵类型是 Eigen::MatrixXf它始终是列优先Eigen::MapEigen::MatrixXf,Eigen::RowMajormat1(data[0][0],2,3);cout\nmat1 is row-major: (mat1.IsRowMajor?true:false\n)endl;coutmat1;cout\n-----------------\n;usingRowMatrixXfEigen::Matrixfloat,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor;Eigen::MapRowMatrixXfmat3(data[0],2,3);coutmat3;// 使用 Eigen 函数//Eigen::MatrixXf mat2 mat.transpose(); // 转置不修改原始数据return0;}输出135246----------------- mat1 is row-major:false135246-----------------123456为什么 IsRowMajor 返回 false因为映射的矩阵类型是 Eigen::MatrixXf它始终是列优先3、stl容器映射到Eigen3.1、一维std::vector映射为Eigen::VectorXf#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){std::vectorfloatvec(10,1.23f);// 10个元素初始化为1.23// 映射 std::vectorEigen::MapEigen::VectorXfvec_map(vec.data(),vec.size());coutvec_map;return0;}3.2、二维std::vector映射为Eigen::VectorXf通过 Eigen::Map 将 std::vector 映射为 Eigen::Matrix。假设你的 std::vector 是一个二维数组你可以利用 std::vector 的底层内存结构即连续的内存块来创建一个映射。扁平化 std::vector首先我们将二维 std::vector 扁平化为一维 std::vector因为 Eigen::Map 只支持一维数组作为输入。#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){// 创建一个 2x3 的 std::vectorvectorvectorfloatvec{{1.0f,2.0f,3.0f},{4.0f,5.0f,6.0f}};// 将二维 std::vector 扁平化为一维数组vectorfloatflat_data;for(constautorow:vec){flat_data.insert(flat_data.end(),row.begin(),row.end());}// 使用 Eigen::Map 映射为 Eigen 矩阵Eigen::MapEigen::MatrixXfmat(flat_data.data(),2,3);// 2行3列coutMapped Eigen Matrix:\n;coutmatendl;return0;}输出Mapped Eigen Matrix:1352464、 Eigen::Matrix 转换为 std::vector要将 Eigen::Matrix 转换为 std::vector我们可以通过访问 Eigen::Matrix 的数据指针并将其复制到 std::vector 中。下面是一个示例#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){// 创建一个 2x3 的 Eigen 矩阵MatrixXfmat(2,3);mat1.0f,2.0f,3.0f,4.0f,5.0f,6.0f;coutOriginal Eigen Matrix:\n;coutmatendl;cout--------------------------\n;// 将 Eigen 矩阵转换为 std::vectorstd::vectorfloatvec(mat.data(),mat.data()mat.size());// 输出转换后的 std::vectorcout\nConverted std::vector:\n;for(floatv:vec){coutv ;}coutendl;cout--------------------------\n;std::vectorfloatvec2;vec2.resize(mat.size());MapVectorXf(vec2.data(),mat.size())MapVectorXf(mat.data(),mat.size());cout\nConverted std::vector:\n;for(floatv:vec2){coutv ;}coutendl;return0;}输出Original Eigen Matrix:123456-------------------------- Converted std::vector:142536-------------------------- Converted std::vector:142536三、注意事项1、为何说它是映射Eigen::Map 并没有复制数据它只是引用了原始数据的内存位置#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){// 创建 2x3 的 MatrixXi 矩阵MatrixXimat(2,3);mat1,2,3,4,5,6;coutmat\nmat;cout\n------------------------\n;// 映射到 mat2Eigen::MapEigen::MatrixXimat2(mat.data(),3,2);// 确保维度与 mat 匹配coutmat2\nmat2;// 清理原矩阵数据cout\n----------清理 mat 数据--------------\n;mat.resize(1,1);// 原矩阵数据清理coutmat\nmatendl;// 映射矩阵 mat2 无效尝试输出会导致错误coutmat2\nmat2endl;// 这时访问 mat2 将导致未定义行为return0;}输出mat123456------------------------mat2154326----------清理 mat 数据--------------mat-842150451mat2-572662307-572662307-572662307-572662307-572662307-572662307Eigen::Map 只是对现有数据的一个视图。当调用 mat.resize(1, 1) 时原始矩阵 mat 的数据被清理并重新分配了这导致映射 mat2 所依赖的数据也消失了。这是因为 Eigen::Map 并没有复制数据它只是引用了原始数据的内存位置。解决方案为了确保数据不丢失映射的矩阵应该在原始矩阵的生命周期内保持有效或者我们可以在清理数据之前将其复制到另一个持久存储结构中。2、明确指定存储顺序RowMajor/ColMajor无效存储顺序问题:MatrixXf 本质是 Matrixfloat, Dynamic, Dynamic, ColMajor添加 Eigen::RowMajor 作为第二个模板参数不会改变存储顺序正确方法是定义新的矩阵类型如 RowMatrixXf#includeiostream#includeEigen/EigenusingnamespaceEigen;usingnamespacestd;intmain(){floatdata[2][3]{{1.0f,2.0f,3.0f},{4.0f,5.0f,6.0f}};// 1. 映射为列优先矩阵默认Eigen::MapEigen::MatrixXfmat(data[0][0],2,3);cout列优先映射 (默认):\nmatendl;cout存储顺序: (mat.IsRowMajor?行优先:列优先)endl;cout\n-----------------\n;// 2. 错误尝试映射为行优先实际无效// 注意MatrixXf 固定为列优先RowMajor 被误解为对齐选项Eigen::MapEigen::MatrixXf,Eigen::RowMajormat1(data[0][0],2,3);cout无效行优先尝试:\n;coutmat1 is row-major: (mat1.IsRowMajor?true:false)endl;coutmat1endl;cout\n-----------------\n;// 3. 正确映射为行优先矩阵usingRowMatrixXfEigen::Matrixfloat,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor;Eigen::MapRowMatrixXfmat3(data[0],2,3);// 注意这里用 data[0]cout正确行优先映射:\nmat3endl;cout存储顺序: (mat3.IsRowMajor?行优先:列优先)endl;return0;}列优先映射(默认):135246存储顺序:列优先-----------------无效行优先尝试:mat1 is row-major:false135246-----------------正确行优先映射:123456存储顺序:行优先data[0][0] vs data[0]:两者完全等价都指向第一个元素 data[0][0] 的地址data[0] 是 float[3] 类型但会自动退化为 float*