C++编译器优化:Copy Elision
为避免对临时对象进行不必要的拷贝,C++编译器常使用一种名为Copy Ellision(拷贝去除)的优化技术,该技术至少包括以下两项内容:
- 返回值优化(RVO),即通过将返回值所占空间的分配地点从被调用端转移至调用端的手段来避免拷贝操作。
返回值优化包括具名返回值优化(NRVO)与无名返回值优化(URVO),两者的区别在于返回值是具名的局部变量还是无名的临时对象。 - 右值拷贝优化,当某一个类类型的临时对象被拷贝赋予同一类型的另一个对象时,通过直接利用该临时对象的方法来避免拷贝操作。
这项优化只能用于右值(临时对象),不能用于左值。
#include <iostream>
struct X
{
X() : id(instances++)
{
std::cout << "X" << id << ": construct\n";
}
X(X const& rhs) : id(instances++)
{
std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **copy**\n";
++copies;
}
// This particular test doesn't exercise assignment, but for
// completeness:
X& operator=(X const& rhs)
{
std::cout << "X" << id << ": <- " << "X" << rhs.id << ": assign\n";
}
~X() { std::cout << "X" << id << ": destroy\n"; }
unsigned id;
static unsigned copies;
static unsigned instances;
};
unsigned X::copies = 0;
unsigned X::instances = 0;
#define CHECK_COPIES( stmt, min, max, comment ) \
{ \
unsigned const old_copies = X::copies; \
\
std::cout << "\n" comment "\n" #stmt "\n===========\n"; \
{ \
stmt; \
} \
unsigned const n = X::copies - old_copies; \
if (n > max) \
std::cout << "*** max is too low or compiler is buggy ***\n"; \
if (n < min) \
std::cout << "*** min is too high or compiler is buggy ***\n"; \
\
std::cout << "-----------\n" \
<< n << "/" << max \
<< " possible copies made\n" \
<< max - n << "/" << max - min \
<< " possible elisions performed\n\n"; \
\
if (n > min) \
std::cout << "*** " << n - min \
<< " possible elisions missed! ***\n"; \
}
struct trace
{
trace(char const* name)
: name(name)
{
std::cout << "->: " << name << "\n";
}
~trace()
{
std::cout << "<-: " << name << "\n";
}
char const* name;
};
void sink(X a)
{
trace t("sink");
}
X nrvo_source()
{
trace t("nrvo_source");
X a;
return a;
}
X urvo_source()
{
trace t("urvo_source");
return X();
}
X identity(X a)
{
trace t("identity");
return a;
}
X lvalue_;
X& lvalue()
{
return lvalue_;
}
typedef X rvalue;
int main()
{
// Double parens prevent "most vexing parse"
CHECK_COPIES( X a(( lvalue() )), 1, 1, "Direct initialization from lvalue");
CHECK_COPIES( X a(( rvalue() )), 0, 1, "Direct initialization from rvalue");
CHECK_COPIES( X a = lvalue(), 1, 1, "Copy initialization from lvalue" );
CHECK_COPIES( X a = rvalue(), 0, 1, "Copy initialization from rvalue" );
CHECK_COPIES( sink( lvalue() ), 1, 1, "Pass lvalue by value" );
CHECK_COPIES( sink( rvalue() ), 0, 1, "Pass rvalue by value" );
CHECK_COPIES( nrvo_source(), 0, 1, "Named return value optimization (NRVO)" );
CHECK_COPIES( urvo_source(), 0, 1, "Unnamed return value optimization (URVO)" );
// Just to prove these things compose properly
CHECK_COPIES( X a(urvo_source()), 0, 2, "Return value used as ctor arg" );
// Expect to miss one possible elision here
CHECK_COPIES( identity( rvalue() ), 0, 2, "Return rvalue passed by value" );
}
- lvalue()函数返回struct X类型的全局变量lvalue_的引用,故lvalue()函数返回左值,可用于测试右值拷贝优化。
- rvalue()函数返回struct X类型的构造器所构建的临时对象,故rvalue()函数返回右值,可用于测试右值拷贝优化。
- nrvo_source()函数返回struct X类型的局部变量a,故nrvo_source()函数可用于测试具名返回值优化。
- urvo_source()函数返回struct X类型的构造器所构建的临时对象,故urvo_source()函数可用于测试无名返回值优化。
- 第109,110行分别用左右值来测试类对象直接初始化中的右值拷贝优化。
- 第112,113行分别用左右值来测试类对象拷贝初始化中的右值拷贝优化。
- 第115,116行分别用左右值来测试普通函数实参中的右值拷贝优化。
- 第118,119行分别用于测试具名返回值优化与无名返回值优化。
Windows平台下使用gcc4.6.1编译运行结果如下
X0: construct
Direct initialization from lvalue
X a(( lvalue() ))
===========
X1: <- X0: **copy**
X1: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Direct initialization from rvalue
X a(( rvalue() ))
===========
X2: construct
X2: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Copy initialization from lvalue
X a = lvalue()
===========
X3: <- X0: **copy**
X3: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Copy initialization from rvalue
X a = rvalue()
===========
X4: construct
X4: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Pass lvalue by value
sink( lvalue() )
===========
X5: <- X0: **copy**
->: sink
<-: sink
X5: destroy
-----------
1/1 possible copies made
0/0 possible elisions performed
Pass rvalue by value
sink( rvalue() )
===========
X6: construct
->: sink
<-: sink
X6: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Named return value optimization (NRVO)
nrvo_source()
===========
->: nrvo_source
X7: construct
<-: nrvo_source
X7: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Unnamed return value optimization (URVO)
urvo_source()
===========
->: urvo_source
X8: construct
<-: urvo_source
X8: destroy
-----------
0/1 possible copies made
1/1 possible elisions performed
Return value used as ctor arg
X a(urvo_source())
===========
->: urvo_source
X9: construct
<-: urvo_source
X9: destroy
-----------
0/2 possible copies made
2/2 possible elisions performed
Return rvalue passed by value
identity( rvalue() )
===========
X10: construct
->: identity
X11: <- X10: **copy**
<-: identity
X11: destroy
X10: destroy
-----------
1/2 possible copies made
1/2 possible elisions performed
*** 1 possible elisions missed! ***
X0: destroy
C++编译器优化:Copy Elision相关推荐
- 一道面试题:你了解哪些编译器优化行为?知道Copy elision 、RVO吗?
C++11以后,g++ 编译器默认开启复制省略(copy elision)选项,可以在以值语义传递对象时避免触发复制.移动构造函数.copy elision 主要发生在两个场景: 函数返回的是值语义时 ...
- c++的复制省略(copy elision)
学习 A simple C++11 Thread Pool 时,发现函数返回了std::future,而std::future的拷贝构造和拷贝赋值都是delete的,感觉有点怪,查了一下,看到 编译器 ...
- C++构造与析构(12) - copy elision编译器优化
目录 1.copy elision说明 2.优化分析 3.如何关闭优化 1.copy elision说明 Copy elision (或Copy omission)是一项编译器优化技术,用于避免不必要 ...
- 浅谈C++11标准中的复制省略(copy elision,也叫RVO返回值优化)
严正声明:本文系作者davidhopper原创,未经许可,不得转载. C++11以及之后的C++14.17标准均提出一项编译优化技术:复制省略(copy elision,也称复制消除),另外还有RVO ...
- C++编程法则365条一天一条(358)copy elision(返回值优化NVO和具名返回值优化NRVO)
文章目录 强制编译器实现的优化 非强制实现优化 参考:https://en.cppreference.com/w/cpp/language/copy_elision Elision 是省略.删节或者忽 ...
- C++ Copy Elision
故事得从 copy/move constructor 说起: The default constructor (12.1), copy constructor and copy assignment ...
- 有保证的复制消除(Guaranteed Copy Elision)
作者:Jonas Devlieghere 原文地址:https://jonasdevlieghere.com/guaranteed-copy-elision/ 新的 C++ 17 标准带来了很多令人兴 ...
- Copy Elision
最近写程序的时候突然意识到了一个(也许大多数人早就意识到的)很常见的问题.我们知道复制一个对象(尤其是复杂的对象/实例)往往需要不小的计算开销(更别提复制一个数组的对象了).但另一方面,复杂对象(群) ...
- C++ Copy Elision 1
故事得从 copy/move constructor 说起: The default constructor (12.1), copy constructor and copy assignment ...
- std::move使用不当引起的copy elision
在使用sonarqube检测C++项目代码时,发现一个使用std::move引起的code smell等级的告警,特记录. 原文内容: Usually, when copying an object, ...
最新文章
- Android SharedPreferences 的使用
- qt工程在linux系统里颜色显示错误_【飞凌嵌入式RK3399开发板试用体验】+QT开发环境搭建测试(二)...
- 逆矩阵 与行列式的关系
- javascript经典实例_提升JavaScript变量的方法有哪些?
- MySQL WHERE:条件查询
- 前端组件化-抽象公共组件类
- codeforces280 C. Game on Tree(期望)
- tcp http socket
- Oracle数据库order by排序查询分页比不分页还慢问题解决办法
- 上传文件到服务器地址怎么配置,文件上传到服务器怎么配置
- celery-分布式任务队列-原理
- 怎样实现banner自动播放html,纯css实现轮播图banner自动轮换效果
- JSON数据格式转换(StringBuffer拼接json串)大全及用法
- ASP.NET自动回发的内幕
- 图形算法 - 模糊函数比较,Blur Function Compare。
- VS2013单元测试
- URLClassLoader加载class到当前线程类加载器【zt】
- p8b75-m修改bios文件_傻瓜式方法:VMWARE使用NAT方式彻底解决开发板无法挂载ubuntu文件的难题...
- 上海工程技术大学c语言商店存货管理系统,商店存货管理系统.docx
- C2——cesium加载城市级三维管网模型的方案