这段代码定义得很好吗?

时间:2011-07-14 01:03:59

标签: c++ c++11 sequence-points operator-precedence

我怀疑根据C ++标准(假设C ++ 0x),以下链接的函数会导致未指定的序列。只是想要确认,如果有人能提供解释,我会很感激。

#include <iostream>

struct TFoo 
{
    TFoo(int) 
    {
        std::cout<<"TFoo"<<std::endl;
    };
    TFoo foobar1(int) 
    {
        std::cout<<"foobar1"<<std::endl;
        return *this;
    };
    TFoo foobar2(int) 
    {
        std::cout<<"foobar2"<<std::endl;
        return *this;
    };
    static int bar1() 
    {
        std::cout<<"bar1"<<std::endl;
        return 0;
    };
    static int bar2() 
    {
        std::cout<<"bar2"<<std::endl;
        return 0;
    };
    static int bar3()
    {
        std::cout<<"bar3"<<std::endl;
        return 0;
    }
};

int main(int argc, char *argv[])
{
    // is the sequence well defined for bar1, bar2 and bar3?
    TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3());
}

* 编辑:删除了函数的__fastcall说明符(不需要/与问题相关)。

2 个答案:

答案 0 :(得分:8)

未指定评估顺序。 C++0x spec草案的有关部分是1.9,第14和15段:

  

14在与要评估的下一个完整表达式相关联的每个值计算和副作用之前,对与完整表达式相关联的每个值计算和副作用进行排序。

     

15除非另有说明,否则对单个算子的操作数和个别表达式的子表达式的评估是不合理的。

此处相关的完整表达式是:

TFoo(TFoo::bar1()).foobar1(TFoo::bar2()).foobar2(TFoo::bar3());

所以对它的子表达式的评价是没有排序的(除非我错过了某个例外)。

我很确定早期的标准包括具有相同效果的语言,但就“序列点”而言。

[编辑]

第15段也说:

  

当调用函数时(无论函数是否为内联函数),在执行每个表达式或语句之前,对与任何参数表达式或指定被调用函数的后缀表达式相关联的每个值计算和副作用进行排序。被调用函数的主体。 [注意:与不同参数表达式相关的值计算和副作用未被排序.-结束注释]

“指定被调用函数的后缀表达式”类似于foo().bar中的foo().bar()

这里的“注释”只是澄清了参数评估顺序“未指定顺序”默认的例外。通过推断,与“指定被调用函数的后缀表达式”相关联的评估顺序也不是;或者如果您愿意,可以使用this参数的表达式的评估顺序。 (如果有异常,这将是指定它的自然位置。或者可能是5.2.2中讨论函数调用。这两个部分都没有说明该示例的评估顺序,因此未指定。)

答案 1 :(得分:1)

是的,函数参数的评估顺序是未指定的。

对我来说,linux上的gcc 4.5.2会产生

bar3
bar2
bar1
TFoo
foobar1
foobar2

但linux上的clang ++和solaris上的gcc 3.4.6

bar1
TFoo
bar2
foobar1
bar3
foobar2

为了分析一个更简单的示例,TFoo(0).foobar1(TFoo::bar2());是对TFoo::foobar1的调用,它带有两个参数:子表达式TFoo(0)的结果(作为隐藏参数this)和子表达式Tfoo::bar2()的结果。对我来说,首先是gcc executs bar2(),然后是TFoo的构造函数,然后调用foobar1(),而clang ++例如首​​先执行TFoo的构造函数,然后执行bar2()然后调用foobar1()