c ++本征3.5,本征图不使用命名返回值优化?

时间:2018-10-05 21:54:29

标签: c++ eigen

我对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;
 }

方法1:

我首先简单地将值传递给函数,然后在函数中,将这些值存储在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

地图的输出显然不是所需的。此外,地图不应指向相同的向量。

方法2:

接下来,我尝试返回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不在这里发生。

方法3:

最后,我尝试返回向量,然后在以下行上初始化地图:

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 ++

预先感谢

1 个答案:

答案 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 ++中的对象生存期有关。您的代码试图通过指向不存在的对象的指针执行操作。