Нужно ли выдавать диагностику для отброшенных выражений значений, которые не имеют побочных эффектов?

После некоторого времени отладки я почувствовал себя глупо, обнаружив глупость в моем коде, которая сводится к чему-то вроде этого:

int main()
{
double p1[] = { 1, 2, 3 };
double p2[] = { 1, 2, 3 };
int color = 1;
bool some_condition = true;

if (some_condition) (p1, p2, color);
}

(p1, p2, color) выражение вычисляется до своего последнего операнда, но должен ли компилятор защищать меня каким-то образом? (Visual Studio ничего не сказала)

И да, вы догадались, я хотел вызвать функцию рисования: Draw(p1, p2, color)

2

Решение

В C ++ выражение (p1, p2, color) заставляет компилятор интерпретировать запятые в скобках как оператор последовательной оценки.
Оператор последовательной оценки является бинарным оператором, который оценивает свой первый операнд как void и отбрасывает результат, затем он оценивает второй операнд и возвращает его значение и тип. Поэтому выражение (p1, p2, color) будет оцениваться следующим образом:

  1. Первый p1 оценивается и отбрасывается, затем (p2, color) оценивается и результат (p2, color) возвращается
  2. Первый p2 оценивается и отбрасывается, затем color оценивается и результат color возвращается

Таким образом, утверждение:

if (some_condition) (p1, p2, color);

Эквивалентно:

if (some_condition) color;

Некоторые компиляторы могут выдавать предупреждение, потому что во время оценки выражения (p1, p2, color) оценки p1 а также p2 приведет к неиспользованию:

CLANG LIVE DEMO
GCC LIVE DEMO
(Как вы уже упоминали Visual Studio не будет предупреждать вообще.)

Помимо этих предупреждений, код является легитимным C ++ (то есть синтаксис C ++ не нарушается).

Вопрос о том, должен ли компилятор защищать вас, спорен. По моему скромному мнению, это должно вас защитить, так как такие выражения, хотя и правильные с точки зрения синтаксиса C ++, могут привести к очень трудным для обнаружения ошибкам (например, в случае сбоя внутри if выражение).

3

Другие решения

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

С правилами стандартов диагностических сообщений мы можем обратиться к проект стандарта C ++ раздел 1.4 Соответствие реализации который говорит (акцент мой):

  1. Набор диагностируемые правила состоят из всех синтаксических и семантических
    правила
    в этом международном стандарте, за исключением тех правил, содержащих
    явное обозначение, что «диагностика не требуется» или которые
    описывается как результат «неопределенного поведения».

  2. Хотя этот международный стандарт устанавливает только требования к C ++
    реализации, эти требования часто легче понять, если
    они сформулированы как требования к программам, частям программ или
    выполнение программ. Такие требования имеют следующее значение:

    • Если программа не содержит нарушений правил в этом международном стандарте, соответствующая реализация
      в пределах своих ресурсов принять и правильно выполнить2 эта программа.

    • Если программа содержит нарушение любого диагностируемого правила или вхождение конструкции, описанной в
      этот стандарт как «условно поддерживаемый», когда реализация не поддерживает эту конструкцию,
      соответствующая реализация выдает хотя бы одно диагностическое сообщение.

    • Если программа содержит нарушение правила, для которого не требуется диагностика, настоящий международный стандарт не устанавливает требований в отношении реализации этой программы.

Эта программа не нарушает синтаксические или семантические правила, поэтому диагностика не требуется.

У нас есть следующий код:

if (some_condition) (p1, p2, color);
^  ^   ^
1  2   3

1 является Выражение-заявление который действителен в этом контексте для и если заявление. Мы можем увидеть это, перейдя к грамматике:

if ( condition ) statement

а также:

statement:
attribute-specifier-seqopt expression-statement

а также:

expression-statement:
expressionopt;

а также:

primary-expression:
( expression )

И то и другое 2 а также 3 являются оператор запятой который оценит левый операнд и отбросит значение, а затем снова вычислит правый операнд, ничего недопустимого здесь.

Так что же раздел 5.18 Оператор запятой говорит:

Пара выражений, разделенных запятой, оценивается слева направо;
левое выражение является выражением отброшенного значения (раздел 5).83

и выражение отброшенного значения покрыто в разделе 5 который говорит:

В некоторых контекстах выражение появляется только для его побочных эффектов.
Такое выражение называется выражением отброшенного значения.

Так как значение результата левого выражения отбрасывается, мы должны заботиться только о побочный эффект. В вашем конкретном случае оценка переменной не имеет другого эффекта, кроме генерации значения, отсюда и предупреждения, но если вы использовали функцию вместо нее, например:

bool func()
{
//...
}

и измените свой код на:

if (some_condition) (func(), func(), func() );

ни clang ни gcc будет предоставлять предупреждение, так как предположительно func будет выполнять некоторые бок-ДЕЙСТВИТЕЛЬНО что тебя волнует

3

По вопросам рекламы [email protected]