return 的值什么时候可以?

When is return by value ok?

我仍然不太确定 return-by-value 在 C++ 中什么时候是个好主意,什么时候不是。在下面的情况下,可以吗?

vector<int> to_vec(const Eigen::MatrixXi& in){
    vector<int> out;
    // copy contents of in into out
    return out;
}

Eigen::MatrixXi to_eigen(const vector<int>& in){
    Eigen::MatrixXi out;
    // copy contents of in into out
    return out
}

根据这些对象 vectorMatrixXi 的实际工作方式,它可能会产生昂贵的副本。另一方面,我假设他们利用 C++ 的 move 功能通过重用底层数据以低成本复制。

在不完全了解实现的情况下,我可以假设什么?

关于 C++ 中 return 值的 Thumb 规则是:

  1. 从不return 对局部变量的引用
  2. 从不 return 指向局部变量的指针
  3. 不要return使用移动语义的命名值

至于 (3) - 这是 C++ 的一个已知问题 - 我们都知道,当一个对象 return 是值时 - 它会激活复制构造函数。这理论上是正确的,但实际上是错误的。启用优化后,编译器将在对象上使用 复制省略

copy elision 是一种优化技术,它使值在调用者范围内而不是在被调用者范围内创建,从而防止昂贵的复制。对该对象的修改将发生在被调用者范围内。

至于 (1) 和 (2),还有一个关于协程和生成器的极端情况,但除非你知道你正在处理它们,否则 (1) 和 (2) 始终有效。

在声明局部变量、初始化它并按值 return 处理它的情况下,您可以非常安全地假设您的编译器将 elide 副本。

这种情况被称为命名return价值优化。本质上,不是在函数调用中分配 return 值,而是在调用站点完成并作为引用传入。按值返回是这里最好的选择,因为你不需要在调用点声明一个变量来传递,但性能会和你一样。

在 C++17 中,copy elision will be mandatory 在大多数情况下涉及纯右值(例如 T t = get_t();return get_t()),但对于 NRVO 仍然是可选的。