条件运算符会导致代码效率降低吗?

时间:2011-08-05 13:41:14

标签: c++ constructor return-value ternary-operator conditional-operator

返回对象时?:代码与if/else相比效率会降低吗?

Foo if_else()
{
    if (bla)
        return Foo();
    else
        return something_convertible_to_Foo;
}

如果bla为false,则返回的Foo直接由something_convertible_to_Foo构建。

Foo question_mark_colon()
{
    return (bla) ? Foo() : something_convertible_to_Foo;
}

此处,return之后的表达式类型为Foo,因此我想首先创建一些临时Foo,如果bla为false则产生结果表达式,然后临时必须进行复制构造以返回函数的结果。那分析听起来不错?

6 个答案:

答案 0 :(得分:8)

必须以任一方式构造临时Foo,并且这两种情况都是RVO的明确候选者,因此我认为没有任何理由相信编译器在这种情况下将无法生成相同的输出。与往常一样,实际编译代码并查看输出是最好的操作过程。

答案 1 :(得分:4)

绝对可以启用右值引用。当两个分支中的一个是左值而另一个是左值时,无论你采用哪种方式,你都不会得到至少其中一个所需的正确函数。当您执行if语句方式时,代码将为返回调用正确的移动或复制构造函数。

答案 2 :(得分:3)

虽然我很欣赏汇编输出,但我仍然发现它们有点“太”低级别:)

以下代码:

struct Foo { Foo(): i(0) {} Foo(int i): i(i) {} int i; };
struct Bar { Bar(double d): d(d) {} double d; operator Foo() const { return Foo(d); } };

Foo If(bool cond) {
  if (cond) { return Foo(); }
  return Bar(3);
}

Foo Ternary(bool cond) {
  return cond ? Foo() : Bar(3);
}

这是Clang生成的LLVM IR

define i64 @If(bool)(i1 zeroext %cond) nounwind readnone {
entry:
  %retval.0.0 = select i1 %cond, i64 0, i64 3     ; <i64> [#uses=1]
  ret i64 %retval.0.0
}

define i64 @Ternary(bool)(i1 zeroext %cond) nounwind readnone {
entry:
  %tmp.016.0 = select i1 %cond, i64 0, i64 3      ; <i64> [#uses=1]
  ret i64 %tmp.016.0
}

顺便说一句,llvm try out demo现在使用了Clang:p

由于这不是第一次以某种形式提出问题,我想记住,因为语义上两种形式都是等价的,所以 good 编译器没有理由就优化和代码生成而言,以不同的方式对待它们。三元运算符只是语法糖。

答案 3 :(得分:2)

与性能问题一样:对手头的案例进行衡量,做任何预测都需要考虑太多事情。

在这里,我不会感到惊讶的是,有些编译器会遇到一种形式或另一种形式的问题,而其他编译器会快速进入相同的内部表示,从而生成完全相同的代码。

答案 4 :(得分:0)

如果两者在逻辑上等同,我会感到惊讶。但这取决于编译器。

答案 5 :(得分:-1)

这取决于编译器。据我所知,在大多数编译器上,if-else它被转换为更清晰的ASM代码并且速度更快。

编辑:假设下面的代码

int a = 10;
int b = 20;
int c = 30;
int d = 30;
int y = 30;

y = (a > b) ? c : d;

if (a > b)
{
    y = c;
}
else
{
    y = d;
}

将像ASM一样翻译

    y = (a > b) ? c : d;
008C13B1  mov         eax,dword ptr [a] 
008C13B4  cmp         eax,dword ptr [b] 
008C13B7  jle         wmain+54h (8C13C4h) 
008C13B9  mov         ecx,dword ptr [c] 
008C13BC  mov         dword ptr [ebp-100h],ecx 
008C13C2  jmp         wmain+5Dh (8C13CDh) 
008C13C4  mov         edx,dword ptr [d] 
008C13C7  mov         dword ptr [ebp-100h],edx 
008C13CD  mov         eax,dword ptr [ebp-100h] 
008C13D3  mov         dword ptr [y],eax 

    if (a > b)
008C13D6  mov         eax,dword ptr [a] 
008C13D9  cmp         eax,dword ptr [b] 
008C13DC  jle         wmain+76h (8C13E6h) 
    {
        y = c;
008C13DE  mov         eax,dword ptr [c] 
008C13E1  mov         dword ptr [y],eax 
    }
    else
008C13E4  jmp         wmain+7Ch (8C13ECh) 
    {
        y = d;
008C13E6  mov         eax,dword ptr [d] 
008C13E9  mov         dword ptr [y],eax 
    }