c++ eigen 3.5,特征图不使用命名 return 值优化?
c++ eigen 3.5, eigen maps don't use named return value optimisation?
我对 C++ 及其特征库还很陌生。
当从函数 returning 特征映射(指向 std::vector)或 returning std::vector 时,我遇到了我认为有点奇怪的行为从一个函数,然后应用一个特征映射到它。我认为这与命名 return 值优化 (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 中,然后 returning 一个指向这个的特征映射(特征矩阵的)向量。
然后我得到了矩阵 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
地图的输出显然不是我们想要的。此外,地图不应该指向同一个向量。
方法二:
接下来我尝试 returning 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 不会在这里发生。
方法三:
最后我尝试 returning 向量,然后在以下行初始化地图:
x_m3:
1 3
2 4
y_m3:
5 7
6 8
x_m3.data():
0xaea150
y_m3.data():
0xaea180
这给出了我想要的结果,我猜 std::vector 上的 NRVO 就是原因。
尝试理解结果:
如前所述,我认为该方法是否给出预期结果的决定因素是 NRVO 是否发生。
对于第三种方法,我知道 NRVO 发生在 std::vector。
我可以看到第二种方法,当函数退出时,向量中的数据可能会被破坏,所以在调用函数中留下了 'dangling vector'(因此我假设 NRVO 为 std::vector 仅当您明确设置函数 return 等于与 return?? 相同类型的向量时才会发生。
并且由于数据被破坏,相同的地址可用于第二次函数调用以存储双精度数(遭受相同的命运)。
所以我想我的主要问题(除了澄清我刚才所做的陈述之外)是,NRVO 不适用于本征图吗?这有什么特别的原因吗?
我正在使用 eigen 3.5,c++11 和 g++
提前致谢
简要查看 Eigen::Map
的文档,我的理解是它是一个非拥有的包装器,围绕着您提供的指针所指向的数据。这使您可以对此数据执行操作,而无需制作额外的数据副本。
正在查看"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);
}
你return一个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 个双打的矢量,并按值 return 它。但是,您随后使用它执行此操作:
Eigen::Map< Eigen::MatrixXd > x_m2(get_vec_test(i1, i2, i3, i4).data(), 2, 2);
从 get_vec_test
编辑的 std::vector<double>
对象 return 是一个临时对象。您提供指向该临时文件中数据的指针 Eigen::Map
。在评估完整表达式 x_m2
的最后,也留下了一个悬空指针,因为临时 std::vector<double>
return 的生命周期从 get_vec_test
结束并且分配了内存数据被释放。不好。
当然,方法 3 完全避免了这种情况,因为您使用这些向量在 Eigen::Map
的生命周期内存储从 get_vec_test
编辑的向量 return。
您看到的问题与 NRVO 无关,与理解 C++ 中的对象生命周期有关。您的代码试图通过指向这些对象的指针对不再存在的对象执行操作。
我对 C++ 及其特征库还很陌生。 当从函数 returning 特征映射(指向 std::vector)或 returning std::vector 时,我遇到了我认为有点奇怪的行为从一个函数,然后应用一个特征映射到它。我认为这与命名 return 值优化 (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 中,然后 returning 一个指向这个的特征映射(特征矩阵的)向量。
然后我得到了矩阵 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
地图的输出显然不是我们想要的。此外,地图不应该指向同一个向量。
方法二:
接下来我尝试 returning 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 不会在这里发生。
方法三:
最后我尝试 returning 向量,然后在以下行初始化地图:
x_m3:
1 3
2 4
y_m3:
5 7
6 8
x_m3.data():
0xaea150
y_m3.data():
0xaea180
这给出了我想要的结果,我猜 std::vector 上的 NRVO 就是原因。
尝试理解结果:
如前所述,我认为该方法是否给出预期结果的决定因素是 NRVO 是否发生。
对于第三种方法,我知道 NRVO 发生在 std::vector。
我可以看到第二种方法,当函数退出时,向量中的数据可能会被破坏,所以在调用函数中留下了 'dangling vector'(因此我假设 NRVO 为 std::vector 仅当您明确设置函数 return 等于与 return?? 相同类型的向量时才会发生。 并且由于数据被破坏,相同的地址可用于第二次函数调用以存储双精度数(遭受相同的命运)。
所以我想我的主要问题(除了澄清我刚才所做的陈述之外)是,NRVO 不适用于本征图吗?这有什么特别的原因吗?
我正在使用 eigen 3.5,c++11 和 g++
提前致谢
简要查看 Eigen::Map
的文档,我的理解是它是一个非拥有的包装器,围绕着您提供的指针所指向的数据。这使您可以对此数据执行操作,而无需制作额外的数据副本。
正在查看"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);
}
你return一个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 个双打的矢量,并按值 return 它。但是,您随后使用它执行此操作:
Eigen::Map< Eigen::MatrixXd > x_m2(get_vec_test(i1, i2, i3, i4).data(), 2, 2);
从 get_vec_test
编辑的 std::vector<double>
对象 return 是一个临时对象。您提供指向该临时文件中数据的指针 Eigen::Map
。在评估完整表达式 x_m2
的最后,也留下了一个悬空指针,因为临时 std::vector<double>
return 的生命周期从 get_vec_test
结束并且分配了内存数据被释放。不好。
当然,方法 3 完全避免了这种情况,因为您使用这些向量在 Eigen::Map
的生命周期内存储从 get_vec_test
编辑的向量 return。
您看到的问题与 NRVO 无关,与理解 C++ 中的对象生命周期有关。您的代码试图通过指向这些对象的指针对不再存在的对象执行操作。