在我们的代码中,有些临时对象正在使用而我们并未察觉;
性能优化时,消除临时对象,特别是大的临时对象,对提升性能效果明显;
这里列出常见的临时对象产生的地方:
按值返回函数结果,结果就是一个临时对象
string add(string s1,string s2) { string s3; s3 = s1+s2; return s3; }
解决方案:在大多数场景下,这个临时对象可以通过按引用返回来消除;
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; }
赋值操作两边不是同一类型时,如果右边可以作为作为的构造函数的参数做隐式转换,那么就会有临时对象的产生;比如:
string s1 = "A";
首先会产生一个临时对象string:string("A");然后赋值给s1: s1 = string("A");
解决方案:
尽量使用相同类型,不用编译器来自动做隐式转换:
比如:
初始化:
string s1("A");
赋值:
string s1; s1.assign("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; }
Posted by: 大CC | 06AUG,2015
博客: blog.me115.com [ 订阅 ]
Github: 大CC