RVO(Return Value Optimization)和NRVO(Named Return Value Optimization)
2016-04-17 15:20
357 查看
中文解释:
RVO:返回值优化 NRVO:具命返回值优化
具体示例如下:
#include <stdio.h>
class A
{
public:
A(int i): m_a(i)
{
printf("constructor\n");
}
A(const A &a)
{
printf("copy constructor\n");
m_a = a.m_a;
}
private:
int m_a;
};
A FunRVO()
{
return A(1);
}
A FunNRVO()
{
A a(1);
return a;
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("begin RVO\n");
A a = FunRVO();
printf("end RVO\n");
printf("\n");
printf("----------------分割线----------------\n");;
printf("\n");
printf("begin NRVO\n");
A b = FunNRVO();
printf("end NRVO\n");
getchar();
return 0;
}
运行结果如下(这是在vs平台下的运行结果,其他平台根据编译器的不同有可能不一样):
begin RVO
constructor
end RVO
----------------分割线----------------
begin NRVO
constructor
copy constructor
end NRVO (这个可能并不是NRVO优化,正常的话结果应该跟RVO优化一样)
关于这两种优化,由于咱对编译器优化并没有过多研究,所以直接从网上copy了一些资料过来:
1. 返回值优化,顾名思义,就是与返回值有关的优化,是当函数是按值返回(而不是引用、指针)时,为了避免产生不必要的临时对象以及值拷贝而进行的优化。
2. 在没有任何“优化”之前,这段代码的行为也许是这样的:return A(1) 这行代码中,构造了一个 A 类的临时的无名对象(姑且叫它t1),接着把 t1 拷贝到另一块临时对象 t2(不在栈上),然后函数保存好 t2 的地址(放在 eax 寄存器中)后返回,FunRVO 的栈区间被“撤消”(这时 t1 也就“没有”了,t1 的生存域在 FunRVO 中,所以被析构了),在
A a = FunRVO(); 这一句中,a 利用 t2 的地址,可以找到 t2 进行,接着进行构造。这样 a 的构造过程就完成了。然后再把 t2 也“干掉”。
可以看到, 在这个过程中,t1 和 t2 这两个临时的对象的存在实在是很浪费的,占用空间不说,关键是他们都只是为a的构造而存在,a构造完了之后生命也就终结了。既然这两个临时的对象对于程序 员来说根本就“看不到、摸不着”(匿名对象),于是编译器干脆在里面做点手脚,不生成它们!怎么做呢?很简单,编译器“偷偷地”在我们写的FunRVO 函数中增加一个参数 A&,然后把 a 的地址传进去(注意,这个时候 a 的内存空间已经存在了,但对象还没有被“构造”,也就是构造函数还没有被调用),然后在函数体内部,直接用a来代替原来的“匿名对象”,在函数体内部就完
成a的构造。这样,就省下了两个临时变量的开销。这就是所谓的“返回值优化”!在 VC7 里,按值返回匿名对象时,默认都是这么做。
3. 具名返回值优化(NRVO)”,是对于按值返回“具名对象”(就是有名字的变量!)时的优化手段,其实道理 是一样的,但由于返回的值是具名变量,情况会复杂很多,所以,能执行优化的条件更苛刻,在下面三种情况下(来自 MSDN),NRVO 将一定不起作用:
a. 不同的返回路径上返回不同名的对象(比如if XXX 的时候返回x,else的时候返回y)
b. 引入 EH 状态的多个返回路径(就算所有的路径上返回的都是同一个具名对象)
c. 在内联asm语句中引用了返回的对象名。
NRVO优化关闭方法(g++下)
g++
-fno-elide-constructors *.cpp
参考:http://blog.sina.com.cn/s/blog_4ab8464c0100kybj.html
http://www.cnblogs.com/xkfz007/articles/2506022.html
RVO:返回值优化 NRVO:具命返回值优化
具体示例如下:
#include <stdio.h>
class A
{
public:
A(int i): m_a(i)
{
printf("constructor\n");
}
A(const A &a)
{
printf("copy constructor\n");
m_a = a.m_a;
}
private:
int m_a;
};
A FunRVO()
{
return A(1);
}
A FunNRVO()
{
A a(1);
return a;
}
int _tmain(int argc, _TCHAR* argv[])
{
printf("begin RVO\n");
A a = FunRVO();
printf("end RVO\n");
printf("\n");
printf("----------------分割线----------------\n");;
printf("\n");
printf("begin NRVO\n");
A b = FunNRVO();
printf("end NRVO\n");
getchar();
return 0;
}
运行结果如下(这是在vs平台下的运行结果,其他平台根据编译器的不同有可能不一样):
begin RVO
constructor
end RVO
----------------分割线----------------
begin NRVO
constructor
copy constructor
end NRVO (这个可能并不是NRVO优化,正常的话结果应该跟RVO优化一样)
关于这两种优化,由于咱对编译器优化并没有过多研究,所以直接从网上copy了一些资料过来:
1. 返回值优化,顾名思义,就是与返回值有关的优化,是当函数是按值返回(而不是引用、指针)时,为了避免产生不必要的临时对象以及值拷贝而进行的优化。
2. 在没有任何“优化”之前,这段代码的行为也许是这样的:return A(1) 这行代码中,构造了一个 A 类的临时的无名对象(姑且叫它t1),接着把 t1 拷贝到另一块临时对象 t2(不在栈上),然后函数保存好 t2 的地址(放在 eax 寄存器中)后返回,FunRVO 的栈区间被“撤消”(这时 t1 也就“没有”了,t1 的生存域在 FunRVO 中,所以被析构了),在
A a = FunRVO(); 这一句中,a 利用 t2 的地址,可以找到 t2 进行,接着进行构造。这样 a 的构造过程就完成了。然后再把 t2 也“干掉”。
可以看到, 在这个过程中,t1 和 t2 这两个临时的对象的存在实在是很浪费的,占用空间不说,关键是他们都只是为a的构造而存在,a构造完了之后生命也就终结了。既然这两个临时的对象对于程序 员来说根本就“看不到、摸不着”(匿名对象),于是编译器干脆在里面做点手脚,不生成它们!怎么做呢?很简单,编译器“偷偷地”在我们写的FunRVO 函数中增加一个参数 A&,然后把 a 的地址传进去(注意,这个时候 a 的内存空间已经存在了,但对象还没有被“构造”,也就是构造函数还没有被调用),然后在函数体内部,直接用a来代替原来的“匿名对象”,在函数体内部就完
成a的构造。这样,就省下了两个临时变量的开销。这就是所谓的“返回值优化”!在 VC7 里,按值返回匿名对象时,默认都是这么做。
3. 具名返回值优化(NRVO)”,是对于按值返回“具名对象”(就是有名字的变量!)时的优化手段,其实道理 是一样的,但由于返回的值是具名变量,情况会复杂很多,所以,能执行优化的条件更苛刻,在下面三种情况下(来自 MSDN),NRVO 将一定不起作用:
a. 不同的返回路径上返回不同名的对象(比如if XXX 的时候返回x,else的时候返回y)
b. 引入 EH 状态的多个返回路径(就算所有的路径上返回的都是同一个具名对象)
c. 在内联asm语句中引用了返回的对象名。
NRVO优化关闭方法(g++下)
g++
-fno-elide-constructors *.cpp
参考:http://blog.sina.com.cn/s/blog_4ab8464c0100kybj.html
http://www.cnblogs.com/xkfz007/articles/2506022.html
相关文章推荐
- hdu 5667 Sequence【费马小定理+矩阵快速幂】
- (LeetCode 307) Range Sum Query - Mutable(Segment Tree)
- hdu 5667 Sequence 矩阵快速幂
- Java常用之String.valueOf、toString、(String)
- UUID
- HDU5667 Sequence
- 共同学习Java源代码--常用工具类--AbstractStringBuilder(一)
- [Data Structure] Maximum Subsequence Sum
- cppreference.com关于值类型的详细解读:lvalue,rvalue,xvalue,prvalue,glvalue
- 设计模式之建造者模式(Builder)
- leetcode——60——Permutation Sequence
- 关于别克2016君越(Buick Lacroesse)的音频系统
- StringBuffer_StringBuilder
- 225. Implement Stack using Queues
- hdu 5667 sequence
- iOS UIScrollView和 cell加载子视图偏移64问题
- HDU 5667 Sequence
- ProgressBar 为什么可以在非UI线程中更新进度。
- 为什么说Druid是“最好的数据库连接池”?体现在哪些方面?这是如何实现的? (mybatis是不自带jdbc链接池的)
- Arduino中的数据类型