在咱们的代码中,有些临时对象正在使用而咱们并未察觉; 性能优化时,消除临时对象,特别是大的临时对象,对提高性能效果明显; 这里列出常见的临时对象产生的地方:ios
按值返回函数结果,结果就是一个临时对象git
string add(string s1,string s2) { string s3; s3 = s1+s2; return s3; }
解决方案: 在大多数场景下,这个临时对象能够经过按引用返回来消除;github
void add(string s1,string s2,string& retvalue ) { retvalue = s1+s2; }
幸运的是,编译器一般会对按值返回作优化,将其改写为按引用返回; 但编译器作的也是很是保守的工做,仅对匿名返回临时对象作这种按引用传递; 以上函数就不会作,而如下函数,编译器会自动优化为按引用传递:性能优化
string add(string s1,string s2) { return s1+s2; }
注:返回值优化(RVO: return value Optimition):由编译器来完成将值返回转换为引用返回;函数
按值传递参数,会有临时对象的分配性能
string add(string s1,string s2) { string s3; s3 = s1+s2; return s3; }
解决方案: 改成按引用传递(若是不但愿函数内部修改,加上const修饰符)优化
string add(const string& s1, const string& s2) { string s3; s3 = s1+s2; return s3; }
赋值操做两边不是同一类型时,若是右边能够做为做为的构造函数的参数作隐式转换,那么就会有临时对象的产生; 好比:this
class Counter { public: Counter(int i):m_nCount(i){ } void setx(){ m_x = 8; } private: int m_nCount; }; Counter c(5); c = 6;
首先会产生一个临时对象Counter :Counter (6); 而后赋值给s1: s1 = Counter (6);spa
解决方案: 尽可能使用相同类型,不用编译器来自动作隐式转换: 好比: 初始化:code
Counter s1(5);
赋值:
Counter s1; s1.setx(6); //若是重载了operator=函数以后,就能够直接使用s1 = 6
注:最开始这里使用string做为示例,但string重载了operator=(char*),所以如下调用不会产生临时对象,感谢@飞龙 指正;
string s1; s1 = "A";
例:
string s3; s3 = s1+ s2;
s1+s2的中间结果须要存到一个临时对象中,而后再赋值给s3;
解决方案: 采用+=操做符,一个个的加上须要的对象:
s3 = s1; s3+= s2;
固然,第一种写法更为优雅,第二种则性能高效; 当此处不是优化关键 路径上的时候,咱们仍是采用第一种写法就好;
class MyClass { MyClass(){ m_a = "A";} private: string m_a; }
成员对象放在构造函数中初始化,那么必然产生一个中间的临时对象;
解决方案: 采用成员初始化列表:
class MyClass { MyClass():m_a("A"){} private: string m_a; }
若是你以为本文对你有所帮助,请点击如下【推荐】按钮, 让更多人阅读;
最直观的方法是编译生产汇编文件,查看汇编代码来查看;但这对汇编语言能力有要求;另外,咱们能够经过直接打印出内存地址来查看(若是是在堆中从新申请的临时对象,内存地址和以前的通常都不同,而若是是在栈中申请的临时对象,可能重用而保持一致,这时能够在类中加入参考变量,经过打印出变量的值来检查是否生成了新的对象。)
示例:
#include <iostream> using namespace std; class Counter { public: Counter(int i):m_nCount(i){ } void setx(){ m_x = 8; } void print(){ printf("m_nCount:%d,m_x:%d,addr:%x \n",m_nCount,m_x,this); } private: int m_nCount; int m_x; }; int main() { Counter c(5); c.setx(); c.print(); c = 6; c.print(); string s1("AAAAAA"); printf("%s,addr:%x \n",s1.data(),s1.data()); s1.assign("bbbbbb"); // 使用赋值,不会新申请空间 printf("%s,addr:%x \n",s1.data(),s1.data()); s1 = "cccccc";// 使用操做符重载函数operator=,不会新申请空间 printf("%s,addr:%x \n",s1.data(),s1.data()); s1 = string("dddddd");//用临时对象直接替换,新空间更改了 printf("%s,addr:%x \n",s1.data(),s1.data()); return 0; }
运行结果:
m_nCount:5,m_x:8,addr:22ff28 m_nCount:6,m_x:-1971344528,addr:22ff28 AAAAAA,addr:8117e4 bbbbbb,addr:8117e4 cccccc,addr:8117e4 dddddd,addr:811804
Posted by: 大CC | 06AUG,2015 博客:blog.me115.com [订阅] Github:大CC