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

62
7

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

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)

спросил(а) 2014-07-28T16:41:00+04:00 5 лет, 8 месяцев назад
1
Решение
73

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

Во- первых p1 оценивается и отбрасывали, а затем (p2, color) вычисляется и результат (p2, color) возвращается. Во- первых 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++, могут привести к очень сложным обнаружению ошибок (например, случай assingment внутри выражения if).

ответил(а) 2014-07-28T16:46:00+04:00 5 лет, 8 месяцев назад
72

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

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

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

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

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

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

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

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

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

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

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

if ( condition ) statement

а также:

statement:
attribute-specifier-seqopt expression-statement

а также:

expression-statement:
expressionopt;

а также:

primary-expression:
( expression )

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

Итак, что говорит раздел 5.18 Comma operator:

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

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

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

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

bool func()
{
//...
}

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

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

ни clang ни gcc не выдают предупреждение, так как предположительно func будет выполнять некоторые побочные эффекты, которые вас волнуют.

ответил(а) 2014-07-28T17:03:00+04:00 5 лет, 8 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема