三元运算符与 if 语句的优点
我正在浏览一些代码,在其中发现了一些三元运算符。这段代码是我们使用的一个库,它应该非常快。
我在想除了空间之外我们是否还可以节省任何东西。
你的经验是什么?
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.
What's your experience?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
性能
三元运算符在性能上不应与编写良好的等效
if
/else
语句不同...它们很可能解析为抽象语法树中的相同表示形式,进行相同的优化等等。您只能做的事情? :
如果您正在初始化常量或引用,或者计算在成员初始化列表中使用哪个值,则不能使用
if
/else
语句,但if
/else
语句不能使用,但 < code>?:
可以是:简洁代码的分解
使用
?
:
的关键原因包括本地化,并避免多余地重复其他内容相同语句/函数调用的部分,例如:...仅比...更好
...如果与非常缺乏经验的程序员打交道,或者某些术语足够复杂以至于
?
:
结构在噪音中迷失了。在更复杂的情况下,例如:等效的
if
/else
:这是编译器可能会也可能不会优化的大量额外函数调用。
此外,
?
允许您选择一个对象,然后使用其成员:等效的
if
/else
将为:Can't named temporaries改进上面的 if/else 怪物吗?
如果表达式
t1
、f1
、t2
等过于冗长而无法重复键入,创建命名临时变量可能会有所帮助,但是:要获得与
?
:
匹配的性能,您可能需要使用std::move
,除非将相同的临时值传递给两个& ;&
参数在调用的函数中:那么你必须避免它。这更加复杂且容易出错。c
?
x:
< strong>y 评估 c,然后评估 x 中的一个,但不是两者都评估> 和 y,这使得在使用指针之前可以安全地说测试指针不是 nullptr,同时提供一些后备值/行为。该代码仅获取实际选择的 x 和 y 中的任何一个的副作用。对于命名临时变量,您可能需要在其初始化过程中使用if
/else
或?
:
来防止执行不需要的代码,或代码执行次数超出预期。功能差异:统一结果类型
考虑:
在上面的条件运算符版本中,
1
经过标准转换为double
,以便类型与2.0
匹配,这意味着即使在true
/1
情况下也会调用is(double)
重载。if
/else
语句不会触发此转换:true
/1
分支调用is (整数)
。您也不能在条件运算符中使用总体类型为
void
的表达式,但它们在if
/else
。强调:需要值的操作之前/之后的值选择
有不同的强调:
if
/else
语句首先强调分支以及要做什么是次要的,而三元运算符则强调要做什么而不是选择要执行的值。在不同的情况下,两者都可以更好地反映程序员对代码的“自然”视角,并使更容易理解、验证和维护。您可能会发现自己根据编写代码时考虑这些因素的顺序来选择其中一个 - 如果您已经开始“做某事”,那么您可能会使用几个(或几个)值中的一个来执行操作它与
?
:
是表达这一点并继续编码“流程”的破坏性最小的方式。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..Things you can only do with ? :
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:Factoring for concise code
Keys reasons to use
?
:
include localisation, and avoiding redundantly repeating other parts of the same statements/function-calls, for example:...is only preferable to...
...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:An equivalent
if
/else
: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:The equivalent
if
/else
would be: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:To get performance matching
?
:
you may need to usestd::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 evaluates c then either but not both of x and y, which makes it safe to say test a pointer isn'tnullptr
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 needif
/else
around or?
:
inside their initialisation to prevent unwanted code executing, or code executing more often than desired.Functional difference: unifying result type
Consider:
In the conditional operator version above,
1
undergoes a Standard Conversion todouble
so that the type matched2.0
, meaning theis(double)
overload is called even for thetrue
/1
situation. Theif
/else
statement doesn't trigger this conversion: thetrue
/1
branch callsis(int)
.You can't use expressions with an overall type of
void
in a conditional operator either, whereas they're valid in statements under anif
/else
.Emphasis: value-selection before/after action needing values
There's a different emphasis:
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".在我看来,三元运算符相对于普通 if 语句的唯一潜在好处是它们能够用于初始化,这对于 const 特别有用:
例如,
如果不使用 if/else 块,则不可能使用 if/else 块来执行此操作还有一个函数 cal。如果您碰巧有很多像这样的 const 情况,您可能会发现正确初始化 const 比使用 if/else 赋值有一点好处。测量一下!但可能甚至无法衡量。我倾向于这样做的原因是因为通过将其标记为 const ,编译器知道我稍后执行的操作可能/会意外地更改我认为已修复的内容。
实际上,我想说的是,三元运算符对于 const 正确性很重要,而 const 正确性是一个很好的习惯:
The only potential benefit to ternary operators over plain if statements in my view is their ability to be used for initializations, which is particularly useful for
const
:E.g.
Doing this with an if/else block is impossible without using a function cal as well. If you happen to have lots of cases of const things like this you might find there's a small gain from initializing a const properly over assignment with if/else. Measure it! Probably won't even be measurable though. The reason I tend to do this is because by marking it const the compiler knows when I do something later that could/would accidentally change something I thought was fixed.
Effectively what I'm saying is that ternary operator is important for const-correctness, and const correctness is a great habit to be in:
嗯...
我用 GCC 和这个函数调用做了一些测试:
使用 gcc -O3 生成的汇编代码有 35 条指令。
使用 if/else + 中间变量的等效代码有 36 个。使用嵌套 if/else 时,使用 3 > 的事实。 2> 1,我得到了 44。我什至没有尝试将其扩展为单独的函数调用。
现在我没有做任何性能分析,也没有对生成的汇编代码进行质量检查,但是对于像这样没有循环等简单的事情,我相信越短越好。
看来三元运算符毕竟还是有一定价值的:-)
当然,前提是代码速度绝对至关重要。嵌套时,if/else 语句比 (c1)?(c2)?(c3)?(c4)?:1:2:3:4 之类的语句更容易阅读。使用巨大的表达式作为函数参数并不有趣。
另请记住,嵌套三元表达式使重构代码(或通过在某个条件下放置一堆方便的 printfs() 进行调试)变得更加困难。
Well...
I did a few tests with GCC and this function call:
The resulting assembler code with gcc -O3 had 35 instructions.
The equivalent code with if/else + intermediate variables had 36. With nested if/else using the fact that 3 > 2 > 1, I got 44. I did not even try to expand this into separate function calls.
Now I did not do any performance analysis, nor did I do a quality check of the resulting assembler code, but at something simple like this with no loops e.t.c. I believe shorter is better.
It appears that there is some value to ternary operators after all :-)
That is only if code speed is absolutely crucial, of course. If/else statements are much easier to read when nested than something like (c1)?(c2)?(c3)?(c4)?:1:2:3:4. And having huge expressions as function arguments is not fun.
Also keep in mind that nested ternary expressions make refactoring the code - or debugging by placing a bunch of handy printfs() at a condition - a lot harder.
如果您从性能角度担心它,那么如果两者之间有任何不同,我会感到非常惊讶。
从外观和感觉的角度来看,这主要取决于个人喜好。如果条件很短并且真/假部分很短,那么三元运算符就可以了,但在 if/else 语句中任何更长的内容往往会更好(在我看来)。
If you're worried about it from a performance perspective then I'd be very surprised if there was any different between the two.
From a look 'n feel perspective it's mainly down to personal preference. If the condition is short and the true/false parts are short then a ternary operator is fine, but anything longer tends to be better in an if/else statement (in my opinion).
您认为两者之间必须有区别,而事实上,有许多语言放弃“if-else”语句而支持“if-else”表达式(在在这种情况下,它们甚至可能没有三元运算符,这不再需要)
想象一下:
无论如何,三元运算符是某些语言(C、C#、C++、Java 等)中的表达式,但没有 有“if-else”表达式,因此它在那里发挥着独特的作用。
You assume that there must be a distinction between the two when, in fact, there are a number of languages which forgo the "if-else" statement in favor of an "if-else" expression (in this case, they may not even have the ternary operator, which is no longer needed)
Imagine:
Anyway, the ternary operator is an expression in some languages (C,C#,C++,Java,etc) which do not have "if-else" expressions and thus it serves a distinct role there.