三元运算符与if语句的漂亮

时间:2010-11-16 08:21:53

标签: c++ if-statement ternary-operator

我正在浏览一些代码,我发现了一些三元运算符。这段代码是我们使用的库,它应该非常快。

我在想,除了那里的空间,我们还要保存任何东西。

你的经历是什么?

5 个答案:

答案 0 :(得分:49)

效果

三元运算符的性能不应与编写良好的等效if / else语句有所区别......它们可能很好地解析为抽象语法树中的相同表示形式,并且相同优化等。

你只能做的事情? :

如果您正在初始化常量或引用,或者计算在成员初始化列表中使用哪个值,则if / else语句不能使用? :可以是:

const int x = f() ? 10 : 2;

X::X() : n_(n > 0 ? 2 * n : 0) { }

保护简明代码

键使用? :的原因包括本地化,并避免冗余地重复相同语句/函数调用的其他部分,例如:

if (condition)
    return x;
else
    return y;

......仅比...更好

return condition ? x : y;

......出于可读性原因,如果与非常缺乏经验的程序员打交道,或者某些术语很复杂,导致? :结构在噪音中丢失。在更复杂的情况下,例如:

fn(condition1 ? t1 : f1, condition2 ? t2 : f2, condition3 ? t3 : f3);

等效if / else

if (condition1)
    if (condition2)
        if (condition3)
            fn(t1, t2, t3);
        else
            fn(t1, t2, f3);
    else if (condition3)
            fn(t1, f2, t3);
        else
            fn(t1, f2, f3);
else
    if (condition2)
       ...etc...

这是编译器可能会或可能不会优化的许多额外函数调用。

无法命名临时改进上面的if / else怪物?

如果表达式t1f1t2等过于冗长而无法重复输入,那么创建命名临时值可能有所帮助,但随后:

  • 要获得性能匹配? :,您可能需要使用std::move,除非将相同的临时值传递给调用函数中的两个&&参数:那你必须避免它。这更复杂,容易出错。

  • c ? x : < em> y 评估 c 然后 x 和< strong> y ,这使得在使用它之前测试指针不是nullptr是安全的,同时提供一些回退值/行为。该代码仅获得实际选择 x y 中的任何一项的副作用。对于已命名的临时对象,您可能需要if / else? :在初始化过程中执行不需要的代码,或者执行代码的次数超出预期。

功能差异:统一结果类型

考虑:

void is(int) { std::cout << "int\n"; }
void is(double) { std::cout << "double\n"; }

void f(bool expr)
{
    is(expr ? 1 : 2.0);

    if (expr)
        is(1);
    else
        is(2.0);
}

在上面的条件运算符版本中,1经历标准转换为double,因此类型匹配2.0,即使is(double)重载也被调用{ {1}} / true情况。 1 / if语句不会触发此转化:else / true分支调用1

您不能在条件运算符中使用总体类型为is(int)的表达式,而它们在void / if下的语句中有效。

重点:需要值的行动之前/之后的价值选择

有一个不同的重点:

else / if语句首先强调分支,并且要做的是次要的,而三元运算符强调要对值的选择要做什么这样做。

在不同的情况下,要么可以更好地反映程序员对代码的“自然”观点,又要更容易理解,验证和维护。根据您在编写代码时考虑这些因素的顺序,您可能会发现自己选择了一个 - 如果您已经启动“做某事”然后发现您可能会使用几个(或几个)值中的一个来做它,else ?是表达最不具破坏性的方式,并继续编写“流程”。

答案 1 :(得分:8)

嗯...

我用GCC做了一些测试,这个函数调用:

add(argc, (argc > 1)?(argv[1][0] > 5)?50:10:1, (argc > 2)?(argv[2][0] > 5)?50:10:1, (argc > 3)?(argv[3][0] > 5)?50:10:1);

使用gcc -O3生成的汇编程序代码有35条指令。

使用if / else +中间变量的等效代码有36.使用嵌套的if / else使用3&gt;的事实2&gt; 1,我得到44.我甚至没有尝试将其扩展为单独的函数调用。

现在我没有进行任何性能分析,也没有对生成的汇编程序代码进行质量检查,但是在这样简单的情况下没有循环e.t.c.我相信越短越好。

毕竟,三元运算符似乎有一些价值: - )

当然,只有代码速度绝对至关重要。如果/ else语句在嵌套时比(c1)更容易阅读?(c2)?(c3)?(c4)?:1:2:3:4。并且将大表达式作为函数参数是有趣。

还要记住,嵌套的三元表达式可以重构代码 - 或者通过在一个条件下放置一堆方便的printfs()来进行调试 - 更加困难。

答案 2 :(得分:7)

在我看来,三元运算符对普通if语句的唯一潜在好处是它们能够用于初始化,这对const特别有用:

E.g。

const int foo = (a > b ? b : a - 10);

如果不使用函数cal,则无法使用if / else块执行此操作。如果你碰巧遇到很多像这样的const事件,你可能会发现使用if / else正确地初始化const有一点点好处。测量它!可能甚至不会被测量。我倾向于这样做的原因是因为通过标记它const,编译器知道我什么时候做某事可能/会意外地改变我认为已修复的东西。

实际上,我所说的是三元运算符对于const正确性很重要,并且const正确性是一个很好的习惯:

  1. 通过让编译器帮助您发现错误
  2. ,可以节省大量时间
  3. 这可能会让编译器应用其他优化

答案 3 :(得分:3)

你认为必须区分两者,事实上,有许多语言放弃了“if-else”语句而支持“if-else”表达式(在这种情况下,它们甚至可能没有三元运算符,不再需要它)

想象:

x = if (t) a else b

无论如何,三元运算符是某些语言(C,C#,C ++,Java等)的表达式,它们具有“if-else”表达式,因此它服务于不同的角色那里。

答案 4 :(得分:1)

如果你从表现的角度对此感到担忧,那么如果两者之间有任何不同,我会感到非常惊讶。

从外观上看,这主要取决于个人偏好。如果条件很短且真/假部分很短,那么三元运算符就可以了,但在if / else语句中(在我看来),任何更长的东西都会更好。