破坏函数参数的顺序是什么?

时间:2016-05-02 21:33:20

标签: c++ function arguments language-lawyer object-lifetime

如果某些函数f分别使用参数p_1,...,p_n类型T_1,...,T_n调用参数a_1 a_n,..., function getPhotoEarnings(){ var earnings = []; var relevantTable = $("a[class='link']").closest("table"); var trs = relevantTable.find("tr"); for(var i=2;i<trs.length-1;i++){ var tds = $(trs[i]).find("td"); var firstId = $(tds[0]).find("a").html(); var firstName = $(tds[1]).find("img").attr("title"); var firstEarned = $(tds[3]).html(); var secondId = $(tds[5]).find("a").html(); var secondName = $(tds[6]).find("img").attr("title"); var secondEarned = $(tds[8]).html(); earnings.push({ "id":firstId, "name":firstName, "earned":firstEarned }); earnings.push({ "id":secondId, "name":secondName, "earned":secondEarned }); } return earnings; } 及其正文抛出异常,完成或返回,参数的破坏顺序是什么?为什么?如果可能,请提供标准参考。

编辑:我实际上想询问函数&#34;参数&#34;,但是作为T.C. Columbo设法澄清了我的困惑,我把这个问题留下来,并问a new separate question about the parameters。有关区别,请参阅有关此问题的评论。

3 个答案:

答案 0 :(得分:21)

我没有在标准中找到答案,但我能够在3个最受欢迎的C ++兼容编译器上进行测试。 R Sahu 的答案几乎解释了它是实现定义的。

  

§5.2.2/8:对后缀表达式和参数的评估都是相对于一个没有排序的   另一个。在输入函数之前,对参数评估的所有副作用进行排序。

Visual Studio C ++编译器(Windows)和gcc(Debian)
参数的构造顺序与其声明相反,并以相反的顺序销毁(因此按照退化的顺序销毁):

  

2
  1
  -1
  -2

Clang(FreeBSD)
参数按其声明顺序构建,并按相反顺序销毁:

  

1
  2
  -2
  -1

所有编译器都被指示将源代码视为C ++ 11,并使用以下代码片段来演示这种情况:

struct A
{
    A(int) { std::cout << "1" << std::endl; }
    ~A() { std::cout << "-1" << std::endl; }
};

struct B
{
    B(double) { std::cout << "2" << std::endl; }
    ~B() { std::cout << "-2" << std::endl; }
};

void f(A, B) { }

int main()
{
    f(4, 5.);
}

答案 1 :(得分:14)

在§5.2.2[4]中N3337对发生的事情非常明确(online draft):

  

在参数初始化期间,实现可以通过将关联参数的转换和/或临时构造与前者相结合来避免构建额外的临时值。   初始化参数(见12.2)。参数的生命周期在定义它的函数返回时结束。

例如在

f(g(h()));

来自调用h()的返回值是一个临时值,将在完整表达式结束时销毁。但是,允许编译器避免这种临时性,并使用其值g()直接初始化。在这种情况下,返回值将在g()返回后被销毁(即在调用f()之前)。

如果我正确理解标准中所述的内容,则不允许将h()返回的值保留到完整表达式的末尾,除非复制(参数)且此副本为g()返回后销毁。

这两种情况是:

  1. h返回值用于直接初始化g参数。 g返回时和调用f之前销毁此对象。
  2. h返回值是暂时的。副本用于初始化g参数,并在g返回时销毁。相反,原始临时表在完整表达式的末尾被销毁。
  3. 我不知道实施是否遵循相关规则。

答案 2 :(得分:11)

标准未指定评估函数参数的顺序。从C ++ 11标准(online draft):

  

5.2.2函数调用

     

8 [注意:后缀表达式和参数表达式的评估都是相对于彼此无法排序的。参数表达式评估的所有副作用在函数之前排序   输入(见1.9)。 -end note ]

因此,完全取决于实现来决定评估函数参数的顺序。反过来,这意味着参数的构造顺序也依赖于实现。

合理的实现会以与构造相反的顺序破坏对象。