【问题标题】:Returning Eigen matrices and temporaries返回特征矩阵和临时矩阵
【发布时间】:2022-01-23 00:04:45
【问题描述】:

考虑以下函数Foo

// ...

Eigen::Vector3d Foo() {
    Eigen::Vector3d res;
    // ...
    return res;
}

int main () {
    Eigen::VectorXd foo = Foo();    // (1)
    return 0;
}

由于返回值优化,(1) 行不应创建任何临时对象。但请考虑以下情况:

// ...

int main () {
    Eigen::VectorXd foo;
    // ...
    foo.head<3>() = Foo();    // (2)
    return 0;
}

(2) 是否创建任何临时对象?更一般地说,像(2) 那样初始化矩阵的任何块是否会创建任何临时对象?如果不是这种情况,那就太好了。否则,我可以重新定义 Foo 如下:

// ...

void AlternativeFoo(Eigen::Ref<Eigen::Vector3d> res) {
    // Modify res
}

int main () {
    Eigen::VectorXd foo;
    // ...
    AlternativeFoo(foo.head<3>());    // (3)
    return 0;
}

(3) 是在不创建临时人员的情况下实现上述目标的唯一方法吗?

【问题讨论】:

  • 不保证NRVO。

标签: c++ eigen3 temporary-objects return-value-optimization


【解决方案1】:

由于返回值优化,第 (1) 行不应创建任何临时对象。

不,它必须实现一个临时的返回值Foo

Foo 的返回类型和变量foo 的类型不匹配(直到 cv-qualification):Vector3d vs VectorXd

但这是允许复制省略的必要条件。 如果不是这样,首先使用的构造函数既不是复制构造函数,也不是移动构造函数。

所以省略不会发生,并且在将要调用的构造函数中,Foo 的返回值绑定到一个引用参数,这将导致临时实现。

(2) 是否创建任何临时对象?更一般地说,在 (2) 中初始化矩阵的任何块是否会创建任何临时对象?

是的,Foo 返回值的临时对象将再次实现,这一次是由于绑定到 operator= 中的引用参数造成的。

是(3)在不创建临时人员的情况下实现上述目标的唯一方法吗?

我会这么认为,但这可能并不重要。 假设Foo 可以内联,那么这种区别可能会变得毫无意义,编译器会判断Foo 中的操作是否可以直接在foo 的存储上执行。

如果不能内联Foo,则复制向量的三个条目不太可能与函数调用有显着相关性。在这种情况下,您的替代解决方案将强制执行额外的间接操作,这可能比复制一些值更昂贵。

【讨论】:

  • 感谢您的回答!所以,(1) 中的 RVO 只有在 foo 恰好是 Eigen::Vector3d 时才有效,对吧?至于您对(3) 方法的cmets,您真的认为与函数调用相比,复制三个向量条目不会那么昂贵吗?如果元素是六个呢?九?你所说的意味着使用Eigen::Ref 仅在向量中有 许多 条目时才方便:这句话真的是真的吗?我希望它始终至少与通过复制相同尺寸的向量一样有效!
  • @fdev 是的,如果类型完全匹配,那么它可以工作。 (3) 是否更高效将取决于我猜的细节。如果向量很大,那么在我看来(3) 可能会有优势,但是内联和优化让我不太清楚哪种变体在哪种尺寸下更可取。我想它需要针对您的具体情况进行基准测试。
  • @fdev 通过内联,我还希望它通常至少与(2) 一样高效。仅在不发生内联的情况下,由于AlternativeFoo 中必要的间接性,可能会产生额外费用。
  • 我明白了,编译器让我更难决定走哪个方向!实现上述最合理的方法是我使用Eigen::Ref,但是如果编译器会让我的努力毫无用处,我为什么要这样做呢? Eigen 官方页面没有提到使用 Eigen::Ref 与标准向量相比的任何真正缺点。
猜你喜欢
  • 1970-01-01
  • 2013-09-25
  • 2018-07-10
  • 1970-01-01
  • 2021-05-11
  • 1970-01-01
  • 1970-01-01
  • 2011-09-29
  • 2016-10-09
相关资源
最近更新 更多