前言
考虑存在这样一个类如HeavyObject,其拷贝赋值操作比较耗时,通常你在使用函数返回这个类的一个对象时会习惯使用哪一种方式?或者会根据具体场景选择某一种方式?
// style 1
HeavyObject func(Args param);
// style 2
bool func(HeavyObject* ptr, Args param);
上面的两种方式都能过到同样的目的,但直观上的使用体验的差别也是非常明显的:
style 1只需要一行代码,而style 2需要两行代码
// style 1
HeavyObject obj = func(params);
// style 2
HeavyObject obj;
func(&obj, params);
但是,能达到同样的目的,消耗的成本却未必是一样的,这取决于多个因素,比如编译器支持的特性、C++语言标准的规范强制性、多团队多环境开发等等。
看起来style 2虽然使用时需要写两行代码,但函数内部的成本却是确定的,只会取决于你当前的编译器,外部即使采用不同的编译器进行函数调用,也并不会有多余的时间开销和稳定性问题。比如func内部使用clang+libc++编译,外部调用的编译环境为gcc+gnustl或者vc++,除了函数调用开销,不用担心其它性能开销以及由于编译环境不同会崩溃问题。
因此这里我主要剖析一下style 1背后开发者需要关注的点。
RVO
RVO是Return Value Optimization的缩写,即返回值优化,NRVO就是具名的返回值优化,为RVO的一个变种,此特性从C++11开始支持,也就是说C++98、C++03都是没有将此优化特性写到标准中的,不过少量编译器在开发过程中也会支持RVO优化(如IBM Compiler?),比如微软是从Visual Studio 2010才开始支持的。
仍然以上述的HeavyObject类为例,为了更清晰的了解编译器的行为,这里实现了构造/析构及拷贝构造、赋值操作、右值构造函数,如下
class HeavyObject
{
public:
HeavyObject() { cout << "Constructor\n"; }
~HeavyObject() { cout << "Destructor\n"; }
HeavyObject(HeavyObject