是否应该针对没有副作用的丢弃值表达式进行诊断?

时间:2014-07-28 13:41:26

标签: c++ debugging warnings comma-operator

经过相当多的调试时间后,我觉得在我的代码中发现一个可以归结为这样的东西的傻了很傻:

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 个答案:

答案 0 :(得分:3)

在C ++中,表达式(p1, p2, color)强制编译器将括号内的逗号解释为顺序评估运算符。 顺序求值运算符是一个二元运算符,它将第一个操作数计算为void并丢弃结果,然后计算第二个操作数并返回其值和类型。因此,表达式(p1, p2, color)将按以下方式进行评估:

  1. 评估并弃置第一个p1,然后评估(p2, color)并返回结果(p2, color)
  2. 评估并弃置第一个p2,然后评估color并返回结果color
  3. 因此声明:

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

    相当于:

    if (some_condition) color;
    

    某些编制者可能会发出警告,因为在评估表达式(p1, p2, color)期间,p1p2的评估将导致未使用:

    CLANG LIVE DEMO GCC LIVE DEMO (正如您已经提到的那样 Visual Studio 根本不会引发任何警告。)

    除了这些警告之外,代码是合法的C ++(即,C ++语法没有被违反)。

    现在,编译器是否应该保护你是有争议的。在我的拙见中,它应该保护你,因为这样的表达虽然从C ++语法的角度来看可能是正确的,但很难发现错误(例如,在if表达式内的分配的情况)。

答案 1 :(得分:3)

这是完全有效的代码,因此编译器不必发出诊断,尽管在这种情况下诊断会有所帮助。这是许多开发人员更喜欢clang的原因之一,因为他们倾向于above what is required when it comes to diagnostic

有关诊断消息的标准规则,我们可以转到draft C++ standard部分1.4 实施合规性强调我的):

  
      
  1. 可诊断规则集包含所有语法和语义   本国际标准中的规则,但包含的规则除外   一个明确的符号“不需要诊断”或哪些是   被描述为导致“未定义的行为”。

  2.   
  3. 虽然本国际标准仅规定了对C ++的要求   实现,如果这些要求通常更容易理解   它们被表达为对节目,节目部分或节目的要求   执行程序。这些要求具有以下含义:

         
        
    • 如果本国际标准中的程序不包含违反规则的行为,则符合规定   应在其资源限制范围内接受并正确执行 2 该程序。

    •   
    • 如果某个程序包含违反任何可诊断规则或某个构造中出现的构造   当实现不支持该构造时,此标准为“有条件支持”,   符合要求的实施应发出至少一条诊断信息。

    •   
    • 如果某个程序违反了不需要诊断的规则,则本国际标准不对该程序的实施提出任何要求。

    •   
  4.   

此程序不违反任何语法或语义规则,因此无需诊断。

我们有以下代码:

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

1是一个表达式语句,在此上下文中有效且 if语句。我们可以通过语法来看到这一点:

if ( condition ) statement

statement:
  attribute-specifier-seqopt expression-statement

expression-statement:
  expressionopt;

primary-expression:
  ( expression )

23都是逗号运算符,它将评估左操作数并丢弃该值,然后再次评估右操作数,此处无效。

那么5.18 逗号运算符部分是什么:

  

用逗号分隔的一对表达式从左到右进行评估;   左表达式是废弃的值表达式(第5条)。 83

废弃值表达式5部分中介绍:

  

在某些情况下,表达式仅出现其副作用。   这样的表达式称为丢弃值表达式。

因为左手表达式的结果值被丢弃,所以我们只关心副作用。在您的特定情况下,评估变量除了生成值之外没有其他影响因此警告,但如果您在其位置使用了函数,例如:

bool func()
{
    //...
}

并将您的代码更改为:

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

clanggcc都不会提供警告,因为大概func会执行您关心的 side-effet