三元运算符与IF语句的优点
我正在浏览一些代码,发现其中有几个三元运算符。此代码是我们使用的库,并且应该相当快。
我在想,除了那里的空间,我们是否节省了任何东西。
您有什么经验?
解决方案
性能
三元运算符的性能不应与编写良好的等效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怪物吗?
如果表达式t1
、f1
、t2
等过于冗长而无法重复键入,创建命名的临时文件可能会有所帮助,但是:
若要获得性能匹配
?
:
,可能需要使用std::move
,除非将相同的临时函数传递给调用的函数中的两个&&
参数:则必须避免使用。这更复杂,也更容易出错。?x :
y评估c,然后评估x和y,代码仅获得实际选择的x和y中任何一个的副作用。对于命名的临时文件,您可能需要在其初始化周围或内部使用if
/else
或?
:
,以防止不需要的代码执行,或者代码执行的频率超过预期。
功能差异:统一结果类型
考虑:
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)
。
您也不能在条件运算符中使用总体类型为void
的表达式,而它们在if
/else
下的语句中有效。
强调:需要值的操作之前/之后的值选择
重点不同:
anif
/else
语句首先强调分支,其次是要执行的操作,而三元运算符强调在选择要执行分支的值时要执行的操作。
在不同的情况下,两者都可以更好地反映程序员对代码的"自然"观点,并使其更易于理解、验证和维护。您可能会发现,您在编写代码时根据考虑这些因素的顺序选择其中一个-如果您已经开始"做某事",那么您可能会使用几个(或几个)值中的一个来完成,?
:
是表达这一点并继续编码"流"的破坏性最小的方式。
相关文章