我们是否应该在c ++中使用临时变量而非用户定义的变量

时间:2014-05-06 10:32:15

标签: c++ optimization compiler-construction

假设有一个c ++函数foo()返回一个布尔值。

我调用此函数来检查属性的状态 或者获取函数调用的结果。

那么调用这类函数的最佳方法是什么。

方法1:

bool flag = foo()
if (flag)
{
   // some code
}
else
{
   // else some code
}

方法2:

if ( foo() )
{
   // some code
}
else
{
   // some code
}

我的问题:使用临时变量是否为编译器提供了更好地优化的机会。

6 个答案:

答案 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 { ... } }

存在语义差异:这些变量的范围不同。

  • 在临时情况下,其生命周期在执行ifelse块之前结束
  • 在命名变量的情况下,其生命周期在其范围的末尾结束,之后else因此

一般而言,从语义上讲,寿命的差异应该可以忽略不计。在某些情况下,它可能很重要:如果您需要访问它或者副作用需要正确排序。

可能会对发出的代码产生一些影响:

  • 对于内置类型:不太可能产生任何影响
  • 表示POD类型:可能没有明确优化
  • 对于非POD类型:析构函数中的副作用(例如释放内存)可能会阻止优化

哪些优化?

嗯,这里可以应用的主要优化是堆栈重用,每当对象的生命周期结束时,编译器应该可以自由地将其内存空间重用于另一个对象(参见{ {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