首页 > 代码库 > C++ &&
C++ &&
1右值引用引入的背景
临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题。但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了CopyElision、RVO(包括NRVO)等编译器优化技术,它们可以防止某些情况下临时对象产生和拷贝。下面简单地介绍一下CopyElision、RVO
CopyElision-----------可以防止不必要的拷贝
1 struct A{ 2 A(int){} 3 A(constA&){} 4 }; 5 A a=42;
上面的创建对象的过程将会分为三步
第一步:为42创建一个临时的对象
第二部:以临时对象为参数拷贝构造a
第三部:析构临时对象
如果A是一个很大的类,那么临时对象的拷贝和析构将会造成很大的内存开销,为什么不直接将42为参数构造a,那么会省略临时对象需要的内存,
CopyElision就是解决这个问题的
测试编译器是否具有CopyElision优化功能:
手写A类的拷贝构造函数(拷贝函数中加打印字符),如果上述没有执行拷贝,说明编译器支持copyelision优化技术
-------------------------------------------------------------------------------------------------------------------------------------------------------
RVO返回值优化技术
struct A { A(int) {} A(const A&) {} }; A get() { return A(1); // tmp1(1) } A a=get();//tmp2
上述代码中,首先会在get函数中产生一个临时对象tmp1,之后以tmp1为参数拷贝构造返回值tmp2,在最后一句中有产生了临时对象tmp2,之后以tmp2为参数拷贝构造a对象
RVO技术就是解决了这种返回值产生的临时对象的拷贝和内存开销
测试,同样可以在代码中手写拷贝构造函数添加输出语句进行测试,如果没有输出,说明编译器支持RVO优化技术
*************************
上述两种优化,如果编译器都支持,虽然不会调用拷贝构造函数,但是拷贝构造函数必须有访问权限,如果写在private里面,编译器会报错
******************
除了返回值优化,你可能还听说过一个叫具名返回值优化(NamedReturnValueOptimization,NRVO)的优化技术,从程序员的角度而言,它其实跟RVO同样的逻辑。只是它的临时对象具有变量名标识,例如修改上述get()函数为:
1 A get() 2 { 3 A tmp(1);//#1 4 5 return tmp; 6 } 7 A a=get();//#2
想想上述修改后A类型共有几次对象构造?虽然#1处看起来有一次显示地构造,#2处看起来也有一次显示地构造,但如果你的编译器支持NRVO和CopyElision,你会发现整个Aa=get();语句的执行过程,只有一次A对象的构造。如果你在get()函数return语句前打印tmp变量的地址,在Aa=get();语句后打印a的地址,你会发现两者地址相同,这就是应用了NRVO技术的结果。
template<typename T> void swap(T &a,T &b) { T tmp(a); a=b; b=tmp; }
我们只是想交换a和b两个对象所拥有的数据,但却不得不使用一个临时对象tmp备份其中一个对象,如果T类型对象拥有指向(或引用)从堆内存分配的数据,那么深拷贝所带来的内存开销是可以想象的。为此,C++11标准引入了右值引用,使用它可以使临时对象的拷贝具有move语意,从而可以使临时对象的拷贝具有浅拷贝般的效率,这样便可以从一定程度上解决临时对象的深度拷贝所带来的效率折损。
//参考 http://www.jb51.net/article/32000.htm !!!!!
C++ &&