C++返回值优化
C++ return value optimization
此代码:
#include <vector>
std::vector<float> getstdvec() {
std::vector<float> v(4);
v[0] = 1;
v[1] = 2;
v[2] = 3;
v[3] = 4;
return v;
}
int main() {
std::vector<float> v(4);
for (int i = 0; i != 1000; ++i)
{
v = getstdvec();
}
}
我在这里的错误理解是,函数getstdvec不应该实际分配它返回的向量。当我在 valgrind/callgrind 中运行它时,我看到有 1001 个调用 malloc;1 表示 main 中的初始向量声明,1000 表示每次循环迭代。
什么给?如何从这样的函数返回向量(或任何其他对象),而不必每次都分配它?
编辑:我知道我可以通过引用传递向量。我的印象是,编写这样的函数是可能的(甚至更可取的),该函数返回对象而不会引起不必要的分配。
调用函数时,对于返回类型(如 std::vector<T>
),编译器为返回的对象提供内存。被调用的函数负责构造它在此内存槽中返回的实例。
RVO/NRVO 现在允许编译器省略创建本地临时对象、从该对象复制构造内存槽中的返回值、销毁临时对象并最终返回给调用方。相反,被调用的函数只是直接在返回槽的内存中构造本地对象,在函数结束时,它只是返回。
从调用方的角度来看,这是透明的:它为返回值提供内存,当调用的函数返回时,有一个有效的实例。调用方现在可以使用此对象,并负责调用析构函数并在以后释放内存。
这意味着 RVO/NRVO 仅在调用函数来构造新实例时有效,而不是在分配它时起作用。以下是可以应用 RVO/NRVO 的示例:
std::vector<float> v = getstdvec();
但是您的原始代码使用循环,并且在每次迭代中,都需要构造getstdvec()
的结果,并将此临时分配给v
。RVO/NRVO 无法删除它。
您可以通过引用传递它...copy elision 使得 v = getstdvect() 将 v(在你的 main)中)直接分配给 v(在你的 getstdvec()中)并跳过通常与按值返回相关的副本,但它不会跳过函数中的 v(4)。为此,您需要通过引用获取向量:
#include <vector>
void getstdvec(std::vector<float>& v){
v.resize(4);//will only realocate if v is wrong size
v[0] = 1; v[1] = 2; v[2] = 3; v[3] = 4;
return v;
}
int main() {
std::vector<float> v(4);
for (int i=0; i!=1000;++i)
getstdvec(v);
}
你在循环中执行复制分配,而不是复制构造。RVO 优化仅适用于从返回值构造变量,而不适用于分配给它们。
我无法完全弄清楚您在这里试图解决的真正问题。有了更多详细信息,也许可以提供解决您潜在问题的良好答案。
就目前而言,要以这种方式从函数返回,您需要创建一个临时向量,以便在每次调用函数时返回。
最简单的答案是将已经创建的向量对象传递到函数中。
std::vector<float> getstdvec(std::vector<float> &myvec){
在这种情况下,您实际上不必将其退回,因此
void getstdvec(std::vector<float> &myvec){
返回值,您可以使用引用:
void getstdvec(std::vector<float> &v)
这样可以避免临时对象的复制
如何从这样的函数返回向量(或任何其他对象),而不必每次都分配它?
按照您的方式,您声明一个大小为 4 的局部向量,因此每次调用该函数时,它都会分配内存。如果您的意思是始终在同一向量上进行修改,那么您可以考虑通过引用传递向量。
例如:
void getstdvec(std::vector<float>& vec)
{ //^^
//do something with vec
}
在 main
中,你声明向量并分配空间。现在,您将执行以下操作:
for (int i=0; i!=1000;++i)
{ //^^^minor: Don't use magic number in the code like this,
//define a const instead
getstdvec(vec);
}
- 返回值优化:显式移动还是隐式
- 使用 std::p air 进行返回值优化
- C++ 特征图3.5,特征图不使用命名返回值优化?
- 我是否正确测试了返回值优化?
- 使用std::optional时的命名返回值优化
- 找不到使保证返回值优化工作的方法
- 局部堆栈变量成员的返回值优化
- 为什么 GCC 无法优化,除非返回值有名称?
- 优化的范围检查并返回值
- 在没有返回值优化的情况下将两个对象加在一起时,将创建多少个临时对象
- 为什么三元运算符阻止返回值优化
- 实现move构造函数如何影响返回值优化
- 内存分配,用于在C 11中循环中函数的返回值:如何优化
- 我如何确定将进行返回值优化
- 返回值优化并复制C中的ELINION
- 如何使编译器不优化 getter 的返回值并使其恒定
- 为什么我在此代码中没有得到返回值优化?
- 如果二进制运算符+重载的返回值是const,它会干扰优化吗
- 了解工厂方法和静态变量赋值的返回值优化 (Visual Studio)
- 返回值优化是否需要声明一个复制构造函数