Тернарный оператор?: Vs if… else


80

В C ++ оператор?: Работает быстрее, чем операторы if () ... else? Есть ли между ними различия в скомпилированном коде?


Сложный вопрос, так как это также будет зависеть от настроек оптимизации компилятора.
extraneon

3
Это, конечно, зависит от того, что вы делаете внутри ветвей. Условный оператор допускает только выражения, в то время как ifпозволяет операторы.
Гамбо


8
Какой-то парень случайно решил отредактировать мой совершенно нормальный вопрос трехлетней давности, переписав вопрос так, чтобы он звучал совершенно не так, как я, и добавил совершенно ненужный код, который делает всю проблему бессмысленной, потому что благодаря постоянному сворачиванию оба этих образца сводятся к простому = 5 дюймов. Возврат.
Xirdus

Ответы:


88

Зависит от вашего компилятора, но на любом современном компиляторе обычно нет разницы. Об этом не стоит беспокоиться. Сконцентрируйтесь на ремонтопригодности вашего кода.


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

4
Что касается ремонтопригодности кода, я бы предпочел if ... else. По крайней мере, мне легче читать.
Exa

2
@Exa: зависит от контекста. При инициализации объекта часто лучше использовать тернарный оператор.
Неманья Трифунович

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

1
@kotlinski, я не говорю, что условное выражение менее обслуживаемо, чем если. Оба они более ясны при определенных, различных обстоятельствах, как описано в ответах на тройной или нет тройной вопрос, связанный выше.
ptomato

106

Это не быстрее. Есть одно отличие, когда вы можете инициализировать постоянную переменную в зависимости от некоторого выражения:

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

Вы не можете сделать то же самое с if-else.


20
@Developer Art: что невозможно с constпеременной.
Job

1
Вы можете создать неконстантную переменную, присвоить ей значение в if / else, затем создать новую константную переменную и сконструировать ее с неконстантной. Скорее расточительно, но отнюдь не невозможно.
Puppy

7
А как насчет старого доброго max? const int x = max(a,b);работает нормально.
bobobobo

3
@bobobobo ха! когда я прочитал ваш комментарий, я подумал, что это команда, которую вы предлагаете, max ? const int x = max(a,b);и подумал: «Эй! Что это за хрень! затем я прочитал его еще раз и заметил, что вопросительный знак не моноширинный! учитывая тему, я думаю, что я был прав, думая о? был частью команды! :)
dewd 05

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? Стандарт С ++ говорит, 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 03 авг.15,

2
@zoujyjs нет, у C такое же правило. Но по правилу «как если бы» компилятор может обманывать, если конечный результат верен. Поэтому, пока нет побочных эффектов, компилятор может выполнить эту оптимизацию.
jalf

Как реализовать if else с cmov? Мов к значению 1 + cmov к значению 2?
Чиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

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" в первой строке на "один")


8
Не нужен даже тернарный оператор:printf("Total: %d item%s", cnt, "s" + (cnt==1));
MSalters

@MSalters но это дает двойной нуль в конце строки, которая может быть проблемой в других ситуациях , когда средство двойной нуль - то (например , в lpStrFilterсоставе OPENFILENAME структур )
bobobobo

1
@bobobobo: No. %sпечатает до, но не включая \0исходную строку.
MSalters

@MSalters, как это printf("Total: %d item%s", cnt, "s" + (cnt==1));работает?
Quirk

2
@Quirk: (cnt==1)истинно или ложно, что преобразуется в 0 или 1. «s» - указатель на строку с завершающим нулем. Добавление одного пропускает один символ (s). Таким образом, это печатает либо «s», либо «».
MSalters


3

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

Хотя синтаксис условного выражения кажется неудобным, это хорошо. Вы вынуждены указать, <false expr>и два выражения проверяются по типу.

Эквивалент if..else.. основанного на выражениях функционального языка, такого как Lisp, Haskell находится ? :на C ++, а не на if..else..операторе.


2

Вы не обязаны помещать все это в одну строку: -

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

Это намного яснее, чем if / else, потому что сразу видно, что обе ветви приводят к назначению x.


Вы также можете инициализировать
константу

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. Хотя весьма вероятно, что скорость оценки условий в обоих сценариях примерно одинакова, изменение области действия заставляет вас принимать во внимание другие факторы, которых позволяет избежать встроенный if.


А как насчет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
Hasturkun

Я хотел просто показать вид кода, чистота одной строки - это хорошо, да. Но если вы хотите увидеть УСЛОВИЕ / НАЗНАЧЕНИЕ, содержание кода может быть подделкой. Если вы хотите определить, что именно, вы смотрите только на оператора и местоположение. Я вижу слово ЕСЛИ и () я знаю, ах, это условие. Я вижу A = B? CONDITION: CONDITION вы сразу заметили это для себя? Большинство людей, которых я знаю по этой программе, не знают, возможно, потому, что большинство людей, которых я знаю по этой программе, такие же новички, как я. Вы правы в том, что цифры - ерунда, в том-то и дело.
Proclyon

2
В первой строке обязательно нужны скобки. Возможно «int x = (y == 1)? 0: 1;» или "int x = ((y == 1)? 0: 1);"
supercat

6
Извините, но у меня нет проблем с просмотром задания. Если вы решите чрезмерно усложнить пример, чтобы выразить свою точку зрения, это ваша проблема. Почему бы вам не написать x = x = 1;везде, а потом пожаловаться, что задание слишком сложное и его следует избегать.
UncleBens

-4

Нет, они преобразуются в один и тот же исполняемый код.


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

3
DeadMG: Очевидно, компилятор VB6!
Alex F
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.