三元运算符与 if 语句的对比

2021-12-12 00:00:00 if-statement ternary-operator c++

我正在浏览一些代码,我在其中发现了一些三元运算符.这段代码是我们使用的一个库,它应该相当快.

I'm browsing through some code and I found a few ternary operators in it. This code is a library that we use, and it's supposed to be quite fast.

我在想我们是否要节省除了空间之外的任何东西.

I'm thinking if we're saving anything except for space there.

你的体验如何?

推荐答案

性能

三元运算符的性能不应与编写良好的等效 if/else 语句不同...它们很可能会解析为 Abstract 中的相同表示语法树,进行相同的优化等.

Performance

The ternary operator shouldn't differ in performance from a well-written equivalent if/else statement... they may well resolve to the same representation in the Abstract Syntax Tree, undergo the same optimisations etc..

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

If you're initialising a constant or reference, or working out which value to use inside a member initialisation list, then if/else statements can't be used but ? : can be:

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

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

简化代码的分解

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

Factoring for concise code

Keys reasons to use ? : include localisation, and avoiding redundantly repeating other parts of the same statements/function-calls, for example:

if (condition)
    return x;
else
    return y;

...只比...更可取

...is only preferable to...

return condition ? x : y;

...基于可读性,如果与非常缺乏经验的程序员打交道,或者某些术语足够复杂以至于 ? : 结构在噪音中迷失了.在更复杂的情况下,例如:

...on readability grounds if dealing with very inexperienced programmers, or some of the terms are complicated enough that the ? : structure gets lost in the noise. In more complex cases like:

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...

编译器可能会或可能不会优化掉很多额外的函数调用.

That's a lot of extra function calls that the compiler may or may not optimise away.

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

Further, ? allows you to select an object, then use a member thereof:

(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 等太冗长而无法重复输入,创建命名临时文件可能会有所帮助,但是:

Can't named temporaries improve the if/else monstrosity above?

If the expressions t1, f1, t2 etc. are too verbose to type repeatedly, creating named temporaries may help, but then:

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

  • To get performance matching ? : you may need to use std::move, except when the same temporary is passed to two && parameters in the function called: then you must avoid it. That's more complex and error-prone.

c ? x : y 评估 c 然后是 x 和 y,这使得在使用它之前测试一个指针不是 nullptr 是安全的,同时提供一些后备值/行为.代码只得到x 和y 中的任何一个实际选择的副作用.对于命名临时文件,您可能需要 if/else? : 在它们的初始化中以防止不需要的代码执行,或者代码执行的频率超出预期.

c ? x : y evaluates c then either but not both of x and y, which makes it safe to say test a pointer isn't nullptr before using it, while providing some fallback value/behaviour. The code only gets the side effects of whichever of x and y is actually selected. With named temporaries, you may need if / else around or ? : inside their initialisation to prevent unwanted code executing, or code executing more often than desired.

考虑:

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

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

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

在上面的条件运算符版本中,1 经历了一个标准转换为 double 以便类型匹配 2.0,这意味着 即使在 true/1 情况下也会调用 is(double) 重载.if/else 语句不会触发此转换:true/1 分支调用 is(int).

In the conditional operator version above, 1 undergoes a Standard Conversion to double so that the type matched 2.0, meaning the is(double) overload is called even for the true/1 situation. The if/else statement doesn't trigger this conversion: the true/1 branch calls is(int).

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

You can't use expressions with an overall type of void in a conditional operator either, whereas they're valid in statements under an if/else.

重点不同:

if/else 语句首先强调分支,要完成的事情是次要的,而三元运算符强调要完成的事情选择要使用的值.

An if/else statement emphasises the branching first and what's to be done is secondary, while a ternary operator emphasises what's to be done over the selection of the values to do it with.

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

In different situations, either may better reflect the programmer's "natural" perspective on the code and make it easier to understand, verify and maintain. You may find yourself selecting one over the other based on the order in which you consider these factors when writing the code - if you've launched into "doing something" then find you might use one of a couple (or few) values to do it with, ? : is the least disruptive way to express that and continue your coding "flow".

相关文章