Тернарний оператор?: Проти якщо… ще


80

У C ++ оператор?: Швидший, ніж оператори if () ... else? Чи є між ними відмінності у складеному коді?


Складне запитання, оскільки це також залежатиме від параметрів оптимізації компілятора.
екстранеон

3
Це, безумовно, залежить від того, що ви робите всередині гілок. Умовний оператор допускає лише вирази, тоді як ifдозволяє оператори.
Гамбо


8
Якийсь хлопець випадковим чином вирішив відредагувати моє цілком нормальне трирічне запитання, переписавши запитання, щоб воно звучало абсолютно несхоже на мене, і додавши абсолютно непотрібний код, який робить цілу проблему безглуздим, оскільки завдяки постійному згортанню обидва ці зразки зводяться до простого "результату" = 5 ". Повернення назад.
Xirdus

Відповіді:


88

Залежить від вашого компілятора, але від будь-якого сучасного компілятора, як правило, немає різниці. Це те, про що вам не варто турбуватися. Зосередьтеся на ремонтопридатності коду.


1
+1 Для багатьох додатків різницю між показниками не варто розглядати навіть на справді складеному компіляторі.

4
Щодо ремонтопридатності коду, я б віддав перевагу, якщо ... інше. Принаймні для мене це легше читати.
Exa,

2
@Exa: Залежить від контексту. Трійковий оператор часто кращий, коли ви ініціалізуєте об'єкт.
Неманья Трифунович

@Nemanja: Тому я сказав "Принаймні для мене". Я просто мав на увазі читабельність коду :)
Exa

1
@kotlinski, я не кажу, що умовна умова є менш ремонтопридатною, ніж if. Вони обидва зрозуміліші за певних, різних, обставин, як це описано у відповідях на тернарне питання чи не на тернарне питання, зв’язане вище.
ptomato

106

Це не швидше. Є одна різниця, коли ви можете ініціалізувати константу змінної залежно від якогось виразу:

const int x = (a<b) ? b : a;

Ви не можете зробити те ж саме з if-else.


20
@Developer Art: Що неможливо за допомогою constзмінної.
Робота

1
Ви можете створити змінну non-const, призначити їй в if / else, потім створити нову змінну const і побудувати її з non-const. Досить марнотратний, але далеко неможливий.
Щеня,

7
А як щодо доброго старого max? const int x = max(a,b);працює просто чудово.
bobobobo

3
@bobobobo ха! коли я прочитав ваш коментар, я подумав, що команда, яку ви пропонували, була, max ? const int x = max(a,b);і подумав що! WTF - це! тоді я прочитав це ще раз і помітив, що знак запитання не є монопростором! зважаючи на тему, я думаю, що мені було виправдано думати? був частиною команди! :)
dewd

2
Можна використовувати const int x = [&] -> int { if (a < b) return b; else return a; }.
LF

43

Я бачив, як GCC перетворює умовний оператор на cmov інструкції (умовного переміщення), а перетворюючи ifоператори на гілки, що означало, що в нашому випадку код був швидшим при використанні умовного оператора. Але це було пару років тому, і, швидше за все, сьогодні, обидва вони компілювалися б до одного коду.

Немає гарантії, що вони скомпілюються до того самого коду. Якщо вам потрібна продуктивність, тоді, як завжди, виміряйте . І коли ви виміряли і виявили, що 1. ваш код занадто повільний, і 2. саме цей шматок коду є винуватцем, тоді вивчіть код збірки, сформований компілятором, і перевірте самі, що відбувається.

Не довіряйте золотим правилам на кшталт "компілятор завжди генеруватиме більш ефективний код, якщо я використовую умовний оператор".


2
+1. Коли я розробляв для PS3, використовуючи GCC, використання умовних умов замість "якщо" було корисним, щоб уникати гілок.
Йохан Котлінський

Це специфічно для мови c? Стандарт c ++ говорить, Only one of the second and third expressions is evaluated. Every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression.що, мабуть, заважає компілятору генерувати cmoveінструкції.
Joey.Z

2
@zoujyjs ні, C має те саме правило. Але за правилом нібито компілятор може вільно обманювати, якщо кінцевий результат правильний. Отже, поки немає побічних ефектів, компілятор може здійснити цю оптимізацію.
jalf

Як реалізувати if ще за допомогою cmov? Mov до значення 1 + a cmov до значення 2?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
ПРИМІТКА: Ця порада застаріла (cira 2010), я не міг відтворити її на gcc 4.4 або пізнішої версії.
ACyclic

15

Вони однакові, однак, тернарний оператор можна використовувати в місцях, де важко використовувати if / else:

printf("Total: %d item%s", cnt, cnt != 1 ? "s" : "");

Виконання цього твердження за допомогою if / else створить зовсім інший скомпільований код.


Оновлення через 8 років ...

Насправді, я думаю, це було б краще:

printf(cnt == 1 ? "Total: %d item" : "Total: %d items", cnt);

(насправді, я майже впевнений, що ви можете замінити "% d" у першому рядку на "one")


8
Навіть не потрібен тернарний оператор:printf("Total: %d item%s", cnt, "s" + (cnt==1));
MSalters

@MSalters, але це дає подвійне значення null у кінці рядка, що може бути проблемою в інших ситуаціях, коли double null щось означає (наприклад, у lpStrFilterчлені структур OPENFILENAME )
bobobobo

1
@bobobobo: Ні. %sдрукує до, але не включаючи \0з вихідного рядка.
MSalters

@MSalters як це printf("Total: %d item%s", cnt, "s" + (cnt==1));працює?
Quirk

2
@Quirk: (cnt==1)true або false, що перетворюється на 0 або 1. "s" - це вказівник на рядок, що закінчується нулем. Додавання одного пропускає один символ (символи). Отже, друкується або "s", або "".
MSalters


3

Незалежно від складеного коду, вони семантично різні речі. <cond>?<true expr>:<false expr>є виразом і if..else..є твердженням.

Хоча синтаксис умовного виразу здається незграбним, це добре. Ви змушені вказати a, <false expr>і два вирази перевіряються типом.

Еквівалент if..else..у функціональній мові на основі виразів, як Lisp, Haskell знаходиться ? :на C ++, а не на if..else..операторі.


2

Ви не змушені ставити все це в один рядок: -

x = y==1 ?
    2
    :// else
    3;

Це набагато зрозуміліше, ніж if / else, тому що ви відразу бачите, що обидві гілки ведуть до того, що x буде призначено.


Ви також можете ініціалізувати const
QuentinUK

0

Я би очікував, що на більшості компіляторів та цільових платформ будуть випадки, коли "якщо" швидше, а випадки, де?: Швидше. Будуть також випадки, коли одна форма є більш-менш компактною, ніж інша. Які випадки надають перевагу тій чи іншій формі, залежать від компіляторів та платформ. Якщо ви пишете критичний для продуктивності код на вбудованому мікро, подивіться, що створює компілятор у кожному випадку, і подивіться, що краще. На "звичайному" ПК через проблеми з кешуванням єдиним способом побачити, що краще, є порівняння обох форм у щось, що нагадує реальний додаток.


0

У CA потрійний оператор "?:" Доступний для побудови умовних виразів форми

exp1 ? exp2:exp3

де exp1, exp2 та exp3 - вирази

наприклад

        a=20;
        b=25;
        x=(a>b)?a:b;

        in the above example x value will be assigned to b;

Це можна записати за допомогою оператора if..else наступним чином

            if (a>b)
             x=a;
             else
             x=b;

** Отже, між ними немає різниці. Це для програміста легко писати, але для компілятора обидва однакові. *


0

Під час реверсування деякого коду (чого я не пам’ятаю кілька років тому) я побачив різницю між рядками машинного коду: а якщо-ще. Don't remember much but it is clear that implementation of both is different.

Але я раджу Вам не вибирати одного з них, оскільки він ефективний, вибирайте відповідно до зручності читання коду. Щасливого кодування


Різниця полягала в тому, що один з них використовував goto для розгалуження, а інший - саоме рідну інструкцію, я не пам’ятаю, хто з яких використовував ..
Первез Алам

0

Тернарний оператор завжди повертає значення. Отже, у ситуації, коли вам потрібне якесь вихідне значення з результату, і є лише 2 умови, завжди краще використовувати тернарний оператор. Використовуйте if-else, якщо будь-яка з вищезазначених умов не відповідає дійсності.


6
Що саме це? Ви знаєте, про що говорите?
квантовий

0

Я думаю, що бувають ситуації, коли вбудований if може дати "швидший" код через область дії, в якій він працює. Створення та знищення об’єктів може коштувати дорого, тому розгляньте наступний сценарій:

class A{
    public:
    A() : value(0) {
        cout << "Default ctor" << endl;
    }
    A(int myInt) : value(myInt)
    {
        cout << "Overloaded ctor" << endl;
    }

    A& operator=(const A& other){
        cout << "= operator" << endl;
        value = other.value; 
    }

    ~A(){
        cout << "destroyed" << std::endl;
    }

    int value;

};


int main()
{
   {
       A a;
       if(true){
           a = A(5);
       }else{
           a = A(10);
       }
   }

   cout << "Next test" << endl;
   {
        A b = true? A(5) : A(10);
   }
   return 0;
}

За допомогою цього коду результат буде:

Default ctor                                                                                                                                                                                                                      
Overloaded ctor                                                                                                                                                                                                                   
= operator                                                                                                                                                                                                                        
destroyed                                                                                                                                                                                                                         
destroyed                                                                                                                                                                                                                         
Next test                                                                                                                                                                                                                         
Overloaded ctor                                                                                                                                                                                                                   
destroyed  

Отже, вставляючи if, ми економимо купу операцій, необхідних для збереження aжиття в тому ж обсязі, що і b. Хоча дуже ймовірно, що швидкість оцінки стану є досить рівною в обох сценаріях, зміна обсягу змушує вас брати до уваги інші фактори, що вбудований дозволяє вам уникати.


А як щодоA a(true ? 5 : 10);
Квест

-1

Зараз я не можу вам у цьому допомогти, можливо, я зможу допомогти з другорядним запитанням під ним, чи хочу я його використовувати? Якщо ви просто хочете знати про швидкість, просто проігноруйте мій коментар.

Все, що я можу сказати, це будь-ласка, будьте дуже розумні, коли використовувати тернар? : оператор. Це може бути як благом, так і прокляттям для читабельності.

Запитайте себе, чи вам це легше читати перед використанням

int x = x == 1 ? x = 1 : x = 1;

if (x == 1)
{
   x = 1
}
else
{
   x = 2
}

if (x == 1)
    x = 1
else
    x = 1

Так, здається дурним робити код на 100% неправдивим. Але цей маленький фокус допоміг мені проаналізувати свою читабельність коду. Це читабельність оператора, який ви розглядаєте в цьому зразку, а не вміст.

ВИДАЄТЬСЯ чистим, але так само як і середнє сидіння унітазу та дверна ручка

На моєму обмеженому досвіді я бачив дуже мало людей, які насправді могли швидко видавати інформацію, необхідну від потрійного оператора, уникати, якщо не впевнені на 100%, що це краще. Я думаю, це виправити біль, коли його також вислуховують


5
перший рядок, мабуть, слід прочитати int x = x == 1 ? 1 : 2або, можливо,int x = (x == 1) ? 1 : 2
Гастуркун

Моя суть полягала лише у тому, щоб показати вигляд коду, чистота одного рядка є приємною, так. Але якщо ви хочете побачити CONDITION / ASSIGNEMENT, вміст коду може бути помилковим. Якщо ви хочете визначити, що саме ви дивитесь на оператора та місце розташування поодинці. Я бачу слово IF та () Я знаю, ах, це умова. Я бачу A = B? УМОВА: УМОВА Ви відразу це помітили для себе? Більшість людей, яких я знаю, що цієї програми не знають, можливо, це тому, що більшість людей, яких я знаю, що ця програма, є новачками, як я. Ви маєте рацію в тому, що цифри є дурницею, ось у чому справа.
Proclyon

2
Перший рядок однозначно потребує дужок. Можливо "int x = (y == 1)? 0: 1;" або "int x = ((y == 1)? 0: 1);"
supercat

6
Вибачте, але у мене немає проблем з переглядом завдання. Якщо ви вирішите занадто ускладнити приклад, щоб висловити свою думку, це ваша проблема. Чому б вам не писати x = x = 1;скрізь, а потім скаржитися, що призначення занадто складне і його слід уникати.
UncleBens

-4

Ні, вони перетворюються на точно такий самий виконуваний код.


7
-1: На якій версії якого компілятора, на якій платформі, з яким кодом?
Щеня,

3
DeadMG: Компілятор VB6, очевидно!
Alex F,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.