我对C ++及其特征库很陌生。 从函数返回本征图(指向std :: vector),或从函数返回std :: vector,然后对其应用本征图时,遇到了我认为有点奇怪的行为。我认为这与命名返回值优化(NRVO)有关。
我玩过三种方法。前两个给出了不想要的结果,而第三个方法给出了我想要的结果(请参见下面的输出)。 这是说明这三种方法的最小工作示例:
int main(){
double i1 = 1, i2 = 2, i3 = 3, i4 = 4, i5 = 5, i6 = 6, i7 = 7, i8 = 8;
//method 1
Eigen::Map< Eigen::MatrixXd > x_m1 = get_map_test(i1, i2, i3, i4);
Eigen::Map< Eigen::MatrixXd > y_m1 = get_map_test(i5, i6, i7, i8);
//method 2
Eigen::Map< Eigen::MatrixXd > x_m2(get_vec_test(i1, i2, i3, i4).data(), 2, 2);
Eigen::Map< Eigen::MatrixXd > y_m2(get_vec_test(i5,i6,i7,i8).data(), 2, 2);
//method 3
std::vector<double> x_v3 = get_vec_test(i1, i2, i3, i4);
std::vector<double> y_v3 = get_vec_test(i5, i6, i7, i8);
Eigen::Map< Eigen::MatrixXd > x_m3(x_v3.data(), 2, 2);
Eigen::Map< Eigen::MatrixXd > y_m3(y_v3.data(), 2, 2);
} //end main
//used in method 1
Eigen::Map< Eigen::MatrixXd > get_map_test(double a, double b, double c, double d) {
std::vector<double> t_v = {a,b,c,d};
return Eigen::Map< Eigen::MatrixXd >(t_v.data(), 2, 2);
}
//used in methods 2 and 3
std::vector<double> get_vec_test(double a, double b, double c, double d) {
std::vector<double> t_v = {a,b,c,d};
return t_v;
}
我首先简单地将值传递给函数,然后在函数中,将这些值存储在std :: vector中,并返回指向该向量的(本征矩阵的)本征图。
然后我得到了矩阵x_m1和y_m1以及它们的.data()值的以下输出:
x_m1:
4.94066e-324 7
4.94066e-324 8
y_m1:
4.94066e-324 7
4.94066e-324 8
x_m1.data():
0xaea150
y_m1.data():
0xaea150
地图的输出显然不是所需的。此外,地图不应指向相同的向量。
接下来,我尝试返回std :: vector,并使用它在与函数return相同的行中初始化地图。
相应的结果是:
x_m2:
4.94066e-324 7
4.94066e-324 8
y_m2:
4.94066e-324 7
4.94066e-324 8
x_m2.data():
0xaea150
y_m2.data():
0xaea150
可以看出,这导致了相同的结果,但是我可以理解为什么NRVO不在这里发生。
最后,我尝试返回向量,然后在以下行上初始化地图:
x_m3:
1 3
2 4
y_m3:
5 7
6 8
x_m3.data():
0xaea150
y_m3.data():
0xaea180
这给出了我想要的结果,我想std :: vector上的NRVO是原因。
如前所述,我认为该方法是否给出理想结果的决定因素是是否发生NRVO。
对于第三种方法,我知道std :: vector会发生NRVO。
对于第二种方法,我可以看到向量可能在函数退出时被破坏了,因此在调用函数中留下了一个“悬挂向量”(因此,我认为std :: vector的NRVO仅在您将函数return显式设置为等于与return ??类型相同的向量。 而且由于数据已被破坏,因此可以将相同的地址用于第二个函数调用来存储双打(命运相同)。
因此,我想我的主要问题(除了澄清我刚才所作的陈述外)是,NRVO是否不适用于本征图?有什么特殊原因吗?
我正在使用本征3.5,c ++ 11和g ++
预先感谢
答案 0 :(得分:3)
简要浏览Eigen::Map
的文档,据我了解,它是围绕您提供的指针所指向的数据的非所有者包装。这样,您就可以对此数据执行操作,而不必制作数据的其他副本。
看“方法1”:
Eigen::Map< Eigen::MatrixXd > get_map_test(double a, double b, double c, double d) {
std::vector<double> t_v = {a,b,c,d};
return Eigen::Map< Eigen::MatrixXd >(t_v.data(), 2, 2);
}
您返回一个Eigen::Map
,其中指针指向向量t_v
分配的内存。当t_v
在函数末尾超出范围时,将释放内存,但是Eigen::Map
仍在映射当前悬空指针所指向的内存。不好。
方法2看起来像这样:
std::vector<double> get_vec_test(double a, double b, double c, double d) {
std::vector<double> t_v = {a,b,c,d};
return t_v;
}
此功能本身不会发生任何不良情况。您只是将4个双打作为向量,然后按值返回。但是,您可以这样做:
Eigen::Map< Eigen::MatrixXd > x_m2(get_vec_test(i1, i2, i3, i4).data(), 2, 2);
从std::vector<double>
返回的get_vec_test
对象是临时的。您将指向该临时目录中的数据的指针提供到Eigen::Map
中。在评估结束时,全表达式x_m2
也留下了一个悬空指针,因为从std::vector<double>
返回的临时get_vec_test
的生存期结束了,分配给数据的内存被释放了。不好。
当然,方法3完全避免了这种情况,因为使用这些向量在get_vec_test
的生命周期内存储了从Eigen::Map
返回的向量。
您看到的问题与NRVO无关,并且全都与了解C ++中的对象生存期有关。您的代码试图通过指向不存在的对象的指针执行操作。