三元运算符与if语句[closed]的联系

问题描述 投票:27回答:5

我正在浏览一些代码,发现其中有一些三元运算符。这段代码是我们使用的库,应该很快。

我在考虑是否要节省那里的空间。

你有什么经验?

c++ if-statement ternary-operator
5个回答
52
投票

性能

[三元运算符的性能不应与编写良好的等价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...

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

此外,?允许您选择一个对象,然后使用其成员:

(f() ? a : b).fn(g() ? c : d).field_name);

等效的if / else为:

if (f())
    if (g())
        x.fn(c.field_name);
    else
        x.fn(d.field_name);
else
    if (g())
        y.fn(c.field_name);
    else
        y.fn(d.field_name);

命名临时人员是否可以改善上述if / else怪癖?

如果表达式t1f1t2等太冗长而无法重复键入,则创建命名临时对象可能会有所帮助,但随后:

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

  • [[[[c

  • ?x:y得出c,然后要么不能同时使用x]和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) / true情况下,也会调用1重载。if/ else语句不会触发此转换:true / 1分支调用is(int)

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

强调:需要价值的行动前后的价值选择

有不同的重点:

if / else语句首先强调分支,而第二要执行的工作,而三元运算符则强调要进行选择的值的选择。

] >在不同的情况下,它们都可以更好地反映程序员对代码的“自然”观点,并使之更易于理解,验证和维护。您可能会发现自己根据编写代码时考虑这些因素的顺序来选择一个-如果您已经开始“做某事”,那么您可能会使用几个(或几个)值中的一个来做它与? :一起使用,是表达它并继续进行编码“流程”的最小破坏性方法。

嗯...

我用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> 2> 1,我得到了44。我什至没有尝试将其扩展为单独的函数调用。

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

看来三元运算符毕竟有一些价值:-)

当然,只有在代码速度绝对至关重要的情况下。如果嵌套时,if / else语句比(c1)?(c2)?(c3)?(c4)?: 1:2:3:4之类的语句容易读得多。将巨大的表达式作为函数参数很有趣。

还请记住,嵌套三元表达式使代码重构-或通过将一堆方便的printfs()置于条件下进行调试-难度大得多。

我认为三元运算符相对于普通if语句的唯一潜在好处是它们可用于初始化的能力,这对const特别有用:
例如

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

如果不使用函数cal也无法使用if / else块执行此操作。如果碰巧有很多类似const的情况,您可能会发现,通过使用if / else赋值正确地初始化const会有一点好处。衡量吧!虽然可能甚至无法测量。我倾向于这样做的原因是因为通过将其标记为const,编译器知道以后我何时执行某些操作可能会/会意外地更改我认为已修复的功能。

有效地说,三元运算符对于const正确性很重要,而const正确性是一个很好的习惯:

[通过让编译器帮助您发现所犯的错误,这节省了很多时间

    这可能会使编译器应用其他优化
  • 您假设
    必须存在两者之间的区别,而实际上,有许多语言放弃了“ if-else”语句,而支持“ if-else”表达式(在此情况下,它们甚至可能没有三元运算符,因此不再需要)

    想象:x = if (t) a else b

    无论如何,三元运算符是某些语言(C,C#,C ++,Java等)的表达式,它们

    not具有“ if-else”表达式,因此它

    具有独特的作用

  • 如果您从性能角度担心它,那么如果两者之间有任何不同,我会感到非常惊讶。
    [从外观上看,这主要取决于个人喜好。如果条件很短,而真/假部分很短,那么三元运算符就可以了,但是在if / else语句中(我认为),任何更长的东西都会变得更好。

    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条指令。

    7
    投票
    例如

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

    如果不使用函数cal也无法使用if / else块执行此操作。如果碰巧有很多类似const的情况,您可能会发现,通过使用if / else赋值正确地初始化const会有一点好处。衡量吧!虽然可能甚至无法测量。我倾向于这样做的原因是因为通过将其标记为const,编译器知道以后我何时执行某些操作可能会/会意外地更改我认为已修复的功能。

    有效地说,三元运算符对于const正确性很重要,而const正确性是一个很好的习惯:

    [通过让编译器帮助您发现所犯的错误,这节省了很多时间


    3
    投票
    必须存在两者之间的区别,而实际上,有许多语言放弃了“ if-else”语句,而支持“ if-else”表达式(在此情况下,它们甚至可能没有三元运算符,因此不再需要)

    想象:x = if (t) a else b

    无论如何,三元运算符是某些语言(C,C#,C ++,Java等)的表达式,它们

    not具有“ if-else”表达式,因此它

    具有独特的作用


    1
    投票
    [从外观上看,这主要取决于个人喜好。如果条件很短,而真/假部分很短,那么三元运算符就可以了,但是在if / else语句中(我认为),任何更长的东西都会变得更好。
    © www.soinside.com 2019 - 2024. All rights reserved.