假设有一个c ++函数foo()返回一个布尔值。
我调用此函数来检查属性的状态 或者获取函数调用的结果。
那么调用这类函数的最佳方法是什么。
方法1:
bool flag = foo()
if (flag)
{
// some code
}
else
{
// else some code
}
方法2:
if ( foo() )
{
// some code
}
else
{
// some code
}
我的问题:使用临时变量是否为编译器提供了更好地优化的机会。
答案 0 :(得分:6)
除非我需要重复使用该标志,否则我通常会进行第二次。确实,在某些情况下它可能对调试很有用,但我不喜欢用编译器能够自己处理的临时变量来污染代码。
解决方法是将所有方法一放在一个块中,以便在if语句之后释放该标志。额外的工作没有结果:我仍然采用方法2。
答案 1 :(得分:4)
优化器将生成相同的内容。旨在实现可读,易懂的代码。我通常更喜欢第一个选项,因为它更容易调试(你可以看到调试器中返回的值)。
答案 2 :(得分:2)
对于原始变量,没有太大的区别。由于优化,它们都会导致生成相同的机器代码。在第一种情况下,结果也是可重用的。
但是,如果返回的类型是带有析构函数的对象。然后,出现差异。对于第一个,对象将被破坏,直到退出其范围(例如,在您的情况下退出函数),对于第二个,它将在if
语句中的评估之后被破坏。
答案 3 :(得分:2)
我更喜欢第一种略有变化的方法:
const bool flag = foo(); // const myclass &cref = foo_returning_object();
if (flag)
{
// some code
}
else
{
// else some code
}
在这种情况下,如果需要,我可以重用返回的值。如果我的临时是一个const引用,它会延长返回对象的生命周期,并且不会对我的程序施加任何开销(constructur /析构函数调用)。
与其他帖子的答案一样,调试返回的值也更容易。
答案 4 :(得分:1)
首先,让我们记住,编译器与我们没有相同的源代码视图: syntax 与它无关,只有语义。因此,我们可以说它有一个相当符号的代码视图。
此外,当优化器开始播放时,它将应用分析和转换,将等效的符号执行转换为等效的二进制文件。
因此,优化的重点是语义。有3种不同的句法形式可用于if
语句:
// with a temporary
if (make()) { ... } else { ... }
// with a variable already in scope
auto var = make();
if (var) { ... } else { ... }
// with a new variable
if (auto var = make()) { ... } else { ... }
后一种语法不适用于:
{ auto var = make(); if (var) { ... } else { ... } }
存在语义差异:这些变量的范围不同。
if
或else
块之前结束else
因此一般而言,从语义上讲,寿命的差异应该可以忽略不计。在某些情况下,它可能很重要:如果您需要访问它或者副作用需要正确排序。
可能会对发出的代码产生一些影响:
哪些优化?
嗯,这里可以应用的主要优化是堆栈重用,每当对象的生命周期结束时,编译器应该可以自由地将其内存空间重用于另一个对象(参见{ {3}})。
如果编译器无法证明该对象不再使用,或者由于其析构函数中的副作用而必须使其保持活动状态,那么它可能必须在该对象的堆栈上占用更多空间。如上所述,当涉及内置类型时,不太可能发生这种情况(优化已开启),但遗憾的是std::string
我不会感到惊讶。
答案 5 :(得分:0)
这取决于具体情况:如果您多次使用该值(并且只需要调用foo一次),或者如果您可以为变量指定一个非常有意义的名称,那么您应该这样做。如果这些都不是真的,那就是风格/偏好。
例子(1):
bool flag = foo();
if (flag) // used once
{
// some code
}
else
{
// else some code
}
bool other_flag = flag && bar(); // used twice: call bar (or not)
// depending on flag
例子(2):
bool foo_available = foo(); // "foo_available" is more explicit than "foo"
// and increases readability
// same code as yours, here