标准 C++11 是否保证传递给函数的临时对象会在函数结束后被销毁?

Does standard C++11 guarantee that temporary object passed to a function will have been destroyed after the end of the function?

众所周知,标准 C++11 保证传递给函数的临时对象将在函数调用之前创建:

但是,标准 C++11 是否保证传递给函数的临时对象会在函数结束后(而不是之前)被销毁?

工作草案,C++ 编程语言标准 2016-07-12:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/n4606.pdf

§ 12.2 Temporary objects

§ 12.2 / 5

There are three contexts in which temporaries are destroyed at a different point than the end of the full expression. The first context is when a default constructor is called to initialize an element of an array with no corresponding initializer (8.6). The second context is when a copy constructor is called to copy an element of an array while the entire array is copied (5.1.5, 12.8). In either case, if the constructor has one or more default arguments, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any. The third context is when a reference is bound to a temporary.

还有:

§ 1.9 / 10

A full-expression is an expression that is not a subexpression of another expression. [ Note: in some contexts, such as unevaluated operands, a syntactic subexpression is considered a full-expression (Clause 5). — end note ] If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition. A call to a destructor generated at the end of the lifetime of an object other than a temporary object is an implicit full-expression. Conversions applied to the result of an expression in order to satisfy the requirements of the language construct in which the expression appears are also considered to be part of the full-expression.

这是否意味着标准 C++11 保证传递给函数的临时对象不会在函数结束之前被销毁 - 并且恰好在完整表达式的末尾?

http://ideone.com/GbEPaK

#include <iostream>
using namespace std;

struct T { 
    T() { std::cout << "T created \n"; }
    int val = 0;
    ~T() { std::cout << "T destroyed \n"; }
};

void function(T t_obj, T &&t, int &&val) {
    std::cout << "func-start \n";
    std::cout << t_obj.val << ", " << t.val << ", " << val << std::endl;
    std::cout << "func-end \n";
}

int main() {

    function(T(), T(), T().val);

    return 0;
}

输出:

T created 
T created 
T created 
func-start 
0, 0, 0
func-end 
T destroyed 
T destroyed 
T destroyed 

我们可以说 T destroyed 总是在 func-end 之后吗?

还有这个:

function(T(), T(), T().val);

是否总是等于:

{
    T tmp1; T tmp2; T tmp3;
    function(tmp1, tmp2, tmp3.val);
}

嗯,您已经引用了所有告诉我们临时生命周期在 完整表达式 结束时结束的文本。所以,是的,“T destroyed”将永远排在最后。

如果破坏没有可观察到的副作用,那么,根据假设规则,它可能 实际上 在之后的任何时间发生……但这没有实际意义,因为,好吧,它不会被观察到。

但是,您提供的最后两个片段通常 并不等同,因为您以一种不同于以前的方式固定了 construction/initialisation 的顺序。函数参数具有未指定的评估顺序。同样,对于这个特定的 T,差异是不可观察的。