您编写的代码的正确性永远不应取决于优化。在规范中使用的C ++“虚拟机”上执行时,它应该输出正确的结果。
但是,您谈论的更多是效率问题。如果使用RVO优化编译器进行优化,您的代码将运行得更好。没关系,出于其他答案中指出的所有原因。
但是,如果您需要这种优化(例如,如果复制构造函数实际上会使您的代码失败),那么您现在就在编译器的无聊之中。
我认为在我自己的实践中,最好的例子是尾部调用优化:
int sillyAdd(int a, int b)
{
if (b == 0)
return a;
return sillyAdd(a + 1, b - 1);
}
这是一个愚蠢的示例,但它显示了一个尾部调用,其中在函数末尾递归地调用一个函数。C ++虚拟机将显示该代码可以正常运行,尽管我可能会引起困惑,因为我为什么要首先编写这样的加法例程。但是,在C ++的实际实现中,我们有一个堆栈,而且空间有限。如果花哨地完成此功能,则必须在添加时将至少b + 1
堆栈帧推入堆栈。如果我要计算sillyAdd(5, 7)
,这没什么大不了的。如果要计算sillyAdd(0, 1000000000)
,可能会引起StackOverflow的麻烦(而不是一种好方法)。
但是,我们可以看到,一旦到达最后一条返回线,就真正完成了当前堆栈框架中的所有操作。我们真的不需要保持它。尾调用优化使您可以“重用”现有的堆栈框架以用于下一个功能。这样,我们只需要1个堆栈框架,而不是b+1
。(我们仍然必须进行所有这些愚蠢的加法和减法,但它们不会占用更多空间。)实际上,优化将代码转换为:
int sillyAdd(int a, int b)
{
begin:
if (b == 0)
return a;
// return sillyAdd(a + 1, b - 1);
a = a + 1;
b = b - 1;
goto begin;
}
在某些语言中,规范明确要求进行尾部调用优化。C ++ 不是其中之一。除非逐案进行,否则我不能依靠C ++编译器来识别这种尾部调用优化机会。在我的Visual Studio版本中,发行版进行了尾部调用优化,而调试版没有(按设计)。
因此,依赖于能够进行计算对我来说是不好的sillyAdd(0, 1000000000)
。