代码之家  ›  专栏  ›  技术社区  ›  hummingBird

三元运算符与if语句的优美性[闭合]

  •  24
  • hummingBird  · 技术社区  · 14 年前

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

    我在想如果我们能节省空间的话。

    你有什么经验?

    5 回复  |  直到 7 年前
        1
  •  50
  •   Tony Delroy    9 年前

    性能

    三元运算符在性能上不应与编写良好的等效运算符不同 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 (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畸形吗?

    如果表达式 t1 , f1 , t2 etc.太冗长,无法重复键入,创建命名的临时文件可能会有帮助,但是:

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

    • c类 ? : 是的 评估 c类 那么要么,但不是两者 是的 ,因此可以安全地说测试指针不是 nullptr 在使用它之前,同时提供一些回退值/行为。代码只会得到 是的 实际上是被选中的。对于指定的临时工,您可能需要 如果 / 其他的 或者 ? : 在它们的初始化中执行不需要的代码,或者代码执行得比期望的更频繁。

    功能差异:统一结果类型

    考虑:

    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个 情况。这个 如果 / 其他的 语句不会触发此转换: 真的 / 1个 分支呼叫 is(int) .

    不能将表达式与 void 在条件运算符中也是,而它们在 如果 / 其他的 .

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

    有一个不同的重点:

    一个 如果 / 其他的 语句首先强调分支,其次才是要做的,而三元运算符则强调在选择要做的值时要做的事情。

    在不同的情况下,这两种方法都可以更好地反映程序员对代码的“自然”透视图,并使其更易于理解、验证和维护。你可能会发现自己在编写代码时根据考虑这些因素的顺序来选择一个而不是另一个——如果你已经开始“做某事”,那么你可能会使用几个(或几个)值中的一个来做, ? : 是表达这一点并继续编码“流”的最没有破坏性的方法。

        2
  •  8
  •   thkala jaxb    14 年前

    好。。。

    我用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。我甚至没有尝试将其扩展为单独的函数调用。

    现在我没有做任何性能分析,也没有对生成的汇编程序代码进行质量检查,但是在这样一个没有循环的简单的地方,我相信更短更好。

    看来三元运算符终究还是有些价值的:-)

    当然,只有在代码速度是绝对关键的情况下。当嵌套时,If/else语句比(c1)这样的语句更容易阅读?(c2)?(c3)?(c4)?:1:2:3:4。把大表达式作为函数参数是 很有趣。

    还要记住,嵌套的三元表达式使得重构代码——或者通过在某个条件下放置一堆方便的printfs()进行调试——困难得多。

        3
  •  7
  •   Flexo - Save the data dump sunny moon    14 年前

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

    例如。

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

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

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

    1. 这可以让编译器帮助您发现所犯的错误,从而节省大量时间
    2. 这可能会让编译器应用其他优化
        4
  •  3
  •   user166390user166390    14 年前

    你认为那里 必须是 当事实上有许多语言放弃“if else”语句而使用“if else”表达式时,两者之间的区别(在这种情况下,它们甚至可能没有不再需要的三元运算符)

    想象:

    x = if (t) a else b
    

    无论如何,三元运算符是一些语言(C,C,C,+,Java等)的表达式。 有“如果有的话”的表达,因此 起着独特的作用 在那里。

        5
  •  1
  •   Sean    14 年前

    如果你从表现的角度担心这一点,那么如果两者之间有什么不同的话,我会非常惊讶。

    从外表和感觉的角度来看,这主要取决于个人喜好。如果条件很短,真/假部分很短,那么三元运算符就可以了,但是在If/else语句中,任何更长的都会更好(在我看来)。