前言注1vc6、vs没有提供编译选项来关闭该优化无论是debug还是release都会进行RVO和复制省略优化注2vc6、vs2005以下及vs2005 Debug上不支持NRVO优化vs2005 Release支持NRVO优化注3g支持这三种优化并且可通过编译选项-fno-elide-constructors来关闭优化RVO12345678910111213141516171819202122232425262728293031#include stdio.hclassA{public:A(){printf(%p construct\n,this);}A(constA cp){printf(%p copy construct\n,this);}~A(){printf(%p destruct\n,this);}};A GetA(){returnA();}intmain(){{A a GetA();}return0;}在g和vc6、vs中上述代码仅仅只会调用一次构造函数和析构函数 输出结果如下0x7ffe9d1edd0f construct0x7ffe9d1edd0f destruct在g中加上-fno-elide-constructors选项关闭优化后输出结果如下0x7ffc46947d4f construct // 在函数GetA中调用无参构造函数A()构造出一个临时变量temp0x7ffc46947d7f copy construct // 函数GetA return语句处把临时变量temp做为参数传入并调用拷贝构造函数A(const A cp)将返回值ret构造出来0x7ffc46947d4f destruct // 函数GetA执行完return语句后临时变量temp生命周期结束调用其析构函数~A()0x7ffc46947d7e copy construct // 函数GetA调用结束返回上层main函数后把返回值变量ret做为参数传入并调用拷贝构造函数A(const A cp)将变量A a构造出来0x7ffc46947d7f destruct // A a GetA()语句结束后返回值ret生命周期结束调用其析构函数~A()0x7ffc46947d7e destruct // A a要离开作用域生命周期结束调用其析构函数~A()注临时变量temp、返回值ret均为匿名变量下面用c代码模拟一下其优化行为123456789101112131415161718192021#include newA GetA(void* p){//由于p的内存是从外部传入的函数返回后仍然有效因此返回值可为A//vs中以下代码还可以写成:// A o *((A*)p);// o.A::A();// return o;return*new(p) A();// placement new}intmain(){{charbuf[sizeof(A)];A a GetA(buf);a.~A();}return0;}NRVOg编译器、vs2005 Release开启/O2及以上优化开关修改上述代码将GetA的实现修改成12345A GetA(){A o;returno;}在g、vs2005 Release中上述代码也仅仅只会调用一次构造函数和析构函数 输出结果如下0x7ffe9d1edd0f construct0x7ffe9d1edd0f destructg加上-fno-elide-constructors选项关闭优化后和上述结果一样0x7ffc46947d4f construct0x7ffc46947d7f copy construct0x7ffc46947d4f destruct0x7ffc46947d7e copy construct0x7ffc46947d7f destruct0x7ffc46947d7e destruct但在vc6、vs2005以下、vs2005 Debug中没有进行NRVO优化输出结果为18fec4 construct // 在函数GetA中调用无参构造函数A()构造出一个临时变量o18ff44 copy construct // 函数GetA return语句处把临时变量o做为参数传入并调用拷贝构造函数A(const A cp)将返回值ret构造出来18fec4 destruct // 函数GetA执行完return语句后临时变量o生命周期结束调用其析构函数~A()18ff44 destruct // A a要离开作用域生命周期结束调用其析构函数~A()下面用c代码模拟一下vc6、vs2005以下、vs2005 Debug上的行为12345678910111213141516171819202122#include newA GetA(void* p){A o;//由于p的内存是从外部传入的函数返回后仍然有效因此返回值可为A//vs中以下代码还可以写成:// A t *((A*)p);// t.A::A(o);// return t;return*new(p) A(o);// placement new}intmain(){{charbuf[sizeof(A)];A a GetA(buf);a.~A();}return0;}注与g、vs2005 Release相比vc6、vs2005以下、vs2005 Debug只优化掉了返回值到变量a的拷贝命名局部变量o没有被优化掉所以最后一共有2次构造和析构的调用复制省略典型情况是调用构造函数进行值类型传参123456789101112voidFunc(A a){}intmain(){{Func(A());}return0;}在g和vc6、vs中上述代码仅仅只会调用一次构造函数和析构函数 输出结果如下0x7ffeb5148d0f construct0x7ffeb5148d0f destruct在g中加上-fno-elide-constructors选项关闭优化后输出结果如下0x7ffc53c141ef construct // 在main函数中调用无参构造函数构造实参变量o0x7ffc53c141ee copy construct // 调用Func函数后将实参变量o做为参数传入并调用拷贝构造函数A(const A cp)将形参变量a构造出来0x7ffc53c141ee destruct // 函数Func执行完后形参变量a生命周期结束调用其析构函数~A()0x7ffc53c141ef destruct // 返回main函数后实参变量o要离开作用域生命周期结束调用其析构函数~A()下面用c代码模拟一下其优化行为123456789101112voidFunc(constA a){}intmain(){{Func(A());}return0;}优化失效的情况开启g优化得到以下各种失效情况的输出结果1根据不同的条件分支返回不同变量1234567891011121314A GetA(boolbflag){A a1, a2;if(bflag)returna1;returna2;}intmain(){A a GetA(true);return0;}0x7ffc3cca324f construct0x7ffc3cca324e construct0x7ffc3cca327f copy construct0x7ffc3cca324e destruct0x7ffc3cca324f destruct0x7ffc3cca327f destruct注12次缺省构造函数调用用于构造a1、a2注21次拷贝构造函数调用用于拷贝构造返回值注3这儿仍然用右值引用优化掉了一次拷贝函数调用返回值赋值给a2返回参数变量3返回全局变量4返回复合数据类型中的成员变量5返回值赋值给已构造好的变量此时会调用operator赋值运算符以上就是详解C编译器优化技术的详细内容