我正在浏览一些代码,我发现了一些三元运算符。这段代码是我们使用的库,它应该非常快。
我在想,除了那里的空间,我们还要保存任何东西。
你的经历是什么?
答案 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...
这是编译器可能会或可能不会优化的许多额外函数调用。
如果表达式t1
,f1
,t2
等过于冗长而无法重复输入,那么创建命名临时值可能有所帮助,但随后:
要获得性能匹配?
:
,您可能需要使用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正确性是一个很好的习惯:
答案 3 :(得分:3)
你认为必须区分两者,事实上,有许多语言放弃了“if-else”语句而支持“if-else”表达式(在这种情况下,它们甚至可能没有三元运算符,不再需要它)
想象:
x = if (t) a else b
无论如何,三元运算符是某些语言(C,C#,C ++,Java等)的表达式,它们不具有“if-else”表达式,因此它服务于不同的角色那里。
答案 4 :(得分:1)
如果你从表现的角度对此感到担忧,那么如果两者之间有任何不同,我会感到非常惊讶。
从外观上看,这主要取决于个人偏好。如果条件很短且真/假部分很短,那么三元运算符就可以了,但在if / else语句中(在我看来),任何更长的东西都会更好。