本章介绍如何使用 Map
类通过不复制数据的方法将原始 C/C++ 数组转换成矩阵或向量
Map类模板参数与构造函数
Map类模板参数如下:
1 | Map<typename MatrixType, int MapOptions = Unaligned, typename StrideType> |
MatrixType
:required
,声明是哪种类型的矩阵或向量MapOptions
:optional
,声明指针是对齐的还是未对齐的StrideType
:optional
,使用Stride
类为内存中的数组自定义布局Stride
类有两个模板参数:1
Stride<OuterStride, InnerStride>
OuterStride
: 指的是 列优先矩阵的两个连续列 或 行优先矩阵的两个连续行 之间的指针增量InnerStride
: 指的是 列优先矩阵的某一列内两个连续行 或 行优先矩阵的某一列内两个连续列 之间的指针增量
1
2
3
4
5
6
7
8
9
10
11int array[8];
for(int i = 0; i < 8; ++i) array[i] = i;
// 默认列优先
cout << "Column-major:\n"
<< Map<Matrix<int,2,4> >(array) << endl;
// 通过定义矩阵类型实现行优先
cout << "Row-major:\n"
<< Map<Matrix<int,2,4,RowMajor> >(array) << endl;
// 通过Stride参数实现行优先
cout << "Row-major using stride:\n"
<< Map<Matrix<int,2,4>, Unaligned, Stride<1,4> >(array) << endl;输出:
1
2
3
4
5
6
7
8
9Column-major:
0 2 4 6
1 3 5 7
Row-major:
0 1 2 3
4 5 6 7
Row-major using stride:
0 1 2 3
4 5 6 7Stride
类还能更灵活:1
2
3
4
5
6int array[24];
for(int i = 0; i < 24; ++i) array[i] = i;
cout << Map<MatrixXi, 0, Stride<Dynamic,2> >
(array, 3, 3, Stride<Dynamic,2>(8, 2))
<< endl;
// 列间隔8,行间隔2输出:
1
2
30 8 16
2 10 18
4 12 20
在构造一个Map类型对象的时候,还需要另外两个信息:指向数组内存空间的指针;目标矩阵/向量的大小。当矩阵/变量类型为固定大小的类型时,第二个信息可以省略。
构造一个Map类型的对象用来转换动态大小的
float
矩阵:其中pf
是一个float*
类型的指针,指向数组内存空间,rows
和cols
则定义了目标矩阵的维度1
Map<MatrixXf> mf(pf, rows, cols);
构造一个Map类型的对象用来转换固定大小的
int
只读向量:其中pi
是一个int*
类型的指针,因为Vector4i
已经说明了向量维度,所以不再需要向构造函数传入向量的维度信息1
Map<const Vector4i> mi(pi);
需要注意的是,Map类并没有默认构造函数,在构造对象的时候,必须告诉构造函数所要转化的数组的地址指针。
Map类型对象的使用
1 | typedef Matrix<float, 1, Dynamic> MatrixType; |
输出:
1 | m1: 0.680375 -0.211234 0.566198 0.59688 0.823295 |
虽然Eigen的所有函数都会像接受其他Eigen类型一样接受Map对象,但在实现自己的函数过程中,从Map对象到其对应的Dense类对象的转换并不会自动完成。具体见 以Eigen类型为参数编写函数
修改映射数组
可以使用C++的 placement new
语法实现在生命Map对象后修改其数组。简而言之,placement new
语法实现的是从给定指针所指向的地址开始创建一个新的对象,一般来说该指针指向的是一片提前申请好的内存,所以也不会进行内存分配。例如:
1 | int data[] = {1,2,3,4,5,6,7,8,9}; |
输出:
1 | The mapped vector v is: 1 2 3 4 |
用这种方法可以在不知道映射数组在内存中位置的情况下构造一个Map对象:
1 | Map<Matrix3f> A(NULL); // don't try to use this matrix yet! |