hum*_*ird 25 c++ if-statement ternary-operator
我正在浏览一些代码,我发现了一些三元运算符.这段代码是我们使用的库,它应该非常快.
我在想,除了那里的空间,我们还要保存任何东西.
你有什么经历?
Ton*_*roy 50
三元运算符的性能不应与编写良好的等效if/ else语句有所区别......它们可能会在抽象语法树中解析为相同的表示形式,进行相同的优化等.
如果您正在初始化常量或引用,或者确定在成员初始化列表中使用哪个值,那么if/ elsestatements不能使用,但? :可以是:
const int x = f() ? 10 : 2;
X::X() : n_(n > 0 ? 2 * n : 0) { }
Run Code Online (Sandbox Code Playgroud)
密钥使用的原因? :包括本地化,并避免冗余地重复相同的语句/函数调用的其他部分,例如:
if (condition)
return x;
else
return y;
Run Code Online (Sandbox Code Playgroud)
......只比......更可取
return condition ? x : y;
Run Code Online (Sandbox Code Playgroud)
......在可读性的基础上,如果处理非常缺乏经验的程序员,或者某些术语足够复杂,? :结构会在噪音中丢失.在更复杂的情况下,例如:
fn(condition1 ? t1 : f1, condition2 ? t2 : f2, condition3 ? t3 : f3);
Run Code Online (Sandbox Code Playgroud)
等价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...
Run Code Online (Sandbox Code Playgroud)
这是编译器可能会或可能不会优化的许多额外函数调用.
如果表达式t1,f1,t2等太冗长重复输入,创建一个名为临时工可能会有帮助,但后来:
要获得性能匹配,? :您可能需要使用std::move,除非将相同的临时值传递给&&名为的函数中的两个参数:那么您必须避免它.这更复杂,更容易出错.
c ? x : y然后评估 c,但不是 x和 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);
}
Run Code Online (Sandbox Code Playgroud)
在上面的条件运算符版本中,1进行标准转换以double使类型匹配2.0,这意味着is(double)即使对于true/ 1situation 也会调用重载.该if/ else语句不触发这个转换:在true/ 1分支呼叫is(int).
您不能void在条件运算符中使用整体类型的表达式,而它们在if/ 下的语句中有效else.
有一个不同的侧重点:
一个if/ else声明强调分支第一,什么是必须做的是次要的,而三元运营商强调什么是所有的值,做它的选择要做.
在不同的情况下,要么可以更好地反映程序员对代码的"自然"观点,又要使其更容易理解,验证和维护.根据您在编写代码时考虑这些因素的顺序,您可能会发现自己选择了一个 - 如果您已经启动"做某事"然后发现您可能会使用几个(或几个)值中的一个来做它是,? :是最不具破坏性的表达方式,并继续你的编码"流程".
好...
我用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);
Run Code Online (Sandbox Code Playgroud)
生成的汇编代码与gcc -O3有35条指令.
使用if/else +中间变量的等效代码有36.使用嵌套的if/else使用3> 2> 1的事实,我得到44.我甚至没有尝试将其扩展为单独的函数调用.
现在我没有进行任何性能分析,也没有对生成的汇编程序代码进行质量检查,但是在没有循环的情况下这样简单的事情我认为更短更好.
看来三元运营商毕竟有一些价值:-)
当然,只有当代码速度绝对至关重要时.如果/ else语句在嵌套时比(c1)更容易读取?(c2)?(c3)?(c4)?:1:2:3:4.拥有巨大的表达式作为函数参数并不好玩.
还要记住,嵌套的三元表达式可以重构代码 - 或者通过在一个条件下放置一堆方便的printfs()来进行调试 - 要困难得多.
在我看来,三元运算符对普通if语句的唯一潜在好处是它们能够用于初始化,这对以下内容特别有用const:
例如
const int foo = (a > b ? b : a - 10);
Run Code Online (Sandbox Code Playgroud)
如果不使用函数cal,则无法使用if/else块执行此操作.如果你碰巧有很多像这样的const事件,你可能会发现使用if/else正确地初始化const有一点小小的好处.测量它!可能甚至不会被测量.我倾向于这样做的原因是因为通过标记它const,编译器知道我什么时候做某事可能/会意外地改变我认为已修复的东西.
实际上,我所说的是三元运算符对于const正确性很重要,并且const正确性是一个很好的习惯:
如果您从性能角度担心它,那么如果两者之间有任何不同,我会感到非常惊讶。
从外观和感觉的角度来看,这主要取决于个人喜好。如果条件很短并且真/假部分很短,那么三元运算符就可以了,但在 if/else 语句中任何更长的内容往往会更好(在我看来)。