1. 返回值优化
在函数需要输出数值时,尽量使用返回值而非输出参数。因为:
- 前者代码直观,容易理解
- 前者两个操作可以在一行写出来,无需中间变量
- 前者性能高,没有不必要的copy
- 后者比较难优化
以下是返回值优化的例子。
1.1. RVO 无名返回值优化
A getA_unnamed()
{
return A;
}
auto a = getA_unnamed();
这段代码只调用一次构造和析构,无copy和move.
可以把copy和move定义为delete,也是同样的效果。
1.2. NRVO 有名字的返回值优化
A getA_named()
{
A a;
return a;
}
auto a = getA_named();
这段代码只调用一次构造和析构,无copy和move.
但是,copy和move至少有一个不能被定义为delete,否则会报错。
1.3. 不确定返回值的优化
A getA_duang()
{
A a1, a2;
if (...) // 编译器无法确定走哪个分支
return a1;
else
return a2;
}
auto a = getA_duang();
这段代码的调用过程为:构造 - 构造 - 移动构造/拷贝构造 - 析构 - 析构 - 析构
说明:移动构造虽然没有分配堆空间,但也是构造工作,因此也有析构函数与之对应。
第三步是移动构造还是拷贝构造看实现。
2. 不能用返回值优化的场景
- 使用例如工厂模式这样的场景,不能返回值类型的数据,只能返回指针类型的数据。此时建议使用
unique_ptr
或shared_ptr
。 - 移动代价很高的对象,也不适合返回值类型,此时建议:
- 堆上分配,然后返回对应的
unique_ptr
- 使用非const引用作为出参
- 递归函数需要反复操作同一容器对象,此时建议将该容器对象作为参数,并按引用传递。
3. 其它
如果函数返回对象,那么怎样返回错误?
答:异常