摘自 ISO C++ 2003 P191
12.2 Temporary Object
1 Temporaries of class type are created in various contexts: binding an rvalue to a reference ( 8.5.3 ), returning an rvalue (6.6.3), a conversion that creates an rvalue (4.1, 5.2.9, 5.2.11, 5.4), throwing an exception (15.1), entering a handler (15.3), and in some initializations (8.5). [Note: the lifetime of exception objects is described in 15.1.] Even when the creation of the temporary object is avoided (12.8), all the semantic restrictions must be respected as if the temporary object was created. [ Example: even if the copy constructor is not called, all the semantic restrictions, such as accessibility (clause 11), shall be satisfied.]
总结:
临时对象产生于引用绑定右值、函数返回右值、转换、抛出异常以及一些初始化试。注,即使有些临时对象可以被优化掉,但语义的要求必须满足
例如:
{
public:
X (const X &a); // No copy constructor definition
} ;
X f()
{
X one;
return one;
}
int main()
{
X one = f(); // VC2005中,release编译时尽管优化掉了复制构造,但仍需要复制构造的存在以满足语义要求
}
2 [Example:
class X {
// ...
public:
// ...
X(int);
X(const X&);
˜X();
};
X f(X);
void g()
{
X a(1);
X b = f(X(2));
a = f(a);
}
Here, an implementation might use a temporary in which to construct X(2) before passing it to f() using X’s copy-constructor; alternatively, X(2) might be constructed in the space used to hold the argument. Also, a temporary might be used to hold the result of f(X(2)) before copying it to b using X’s copyconstructor; alternatively, f()’s result might be constructed in b. On the other hand, the expression a=f(a) requires a temporary for either the argument a or the result of f(a) to avoid undesired aliasing of a. ]
总结:
对于f(X(2))这样形式的参数传入和值的返回,并不一定必须产生临时对象,然后由复制构造来构造,也可以直接在目标内存中构造(形参或接受返回值的对象的所在地址)。这就是说,可以不经复制构造而直接构造对象,但如之前所说复制构造必须存在。
3 When an implementation introduces a temporary object of a class that has a non-trivial constructor (12.1), it shall ensure that a constructor is called for the temporary object. Similarly, the destructor shall be called for a temporary with a non-trivial destructor (12.4). Temporary objects are destroyed as the last step in evaluating the full-expression (1.9) that (lexically) contains the point where they were created. This is true even if that evaluation ends in throwing an exception.
总结:
当产生临时对象的完整表达式计算完时,临时对象就会被析构
4 There are two contexts in which temporaries are destroyed at a different point than the end of the full-expression. The first context is when an expression appears as an initializer for a declarator defining an object.In that context,the temporary that holds the result of the expression shall persist until the object’s initialization is complete. The object is initialized from a copy of the temporary; during this copying, an implementation can call the copy constructor many times; the temporary is destroyed after it has been copied, before or when the initialization completes. If many temporaries are created by the evaluation of the initializer, the temporaries are destroyed in reverse order of the completion of their construction.
总结:
有两个情况下,不在完整表达式完成时析构。第一种情况是,当一个表达式出现在初始化式中时,当执行完初始化之后才会析构
例如:
{
X a,b;
X c;
cout << "----------"<<endl;
c=a+b; // 临时对象在对c进行完赋值后析构,即临时对象在下面语句执行前析构
cout << "----------"<<endl;
}
5 The second context is when a reference is bound to a temporary. The temporary to which the reference is bound or the temporary that is the complete object to a subobject of which the temporary is bound persists for the lifetime of the reference except as specified below. A temporary bound to a reference member in a constructor’s ctor-initializer ( 12.6.2 ) persists until the constructor exits.A temporary bound to a reference parameter in a function call ( 5.2.2 ) persists until the completion of the full expression containing the call.A temporary bound to the returned value in a function return statement ( 6.6.3 ) persists until the function exits.In all these cases, the temporaries created during the evaluation of the expression initializing the reference, except the temporary to which the reference is bound,are destroyed at the end of the full-expression in which they are created and in the reverse order of the completion of their construction.If the lifetime of two or more temporaries to which references are bound ends at the same point, these temporaries are destroyed at that point in the reverse order of the completion of their construction. In addition, the destruction of temporaries bound to references shall take into account the ordering of destruction of objects with static or automatic storage duration ( 3.7.1 , 3.7.2); that is, if obj1 is an object with static or automatic storage duration created before the temporary is created, the temporary shall be destroyed before obj1 is destroyed; if obj2 is an object with static or automatic storage duration created after the temporary is created, the temporary shall be destroyed after obj2 is destroyed.[Example:
class C {
// ...
public:
C();
C(int);
friend C operator+(const C&, const C&);
˜C();
};
C obj1;
const C& cr = C(16)+C(23);
C obj2;
the expression C(16) + C(23) creates three temporaries. A first temporary T1 to hold the result of the expression C(16), a second temporary T2 to hold the result of the expression C(23), and a third temporary T3 to hold the result of the addition of these two expressions. The temporary T3 is then bound to the reference cr.It is unspecified whether T1 or T2 is created first. On an implementation where T1 is created before T2, it is guaranteed that T2 is destroyed before T1. The temporaries T1 and T2 are bound to the reference parameters of operator+; these temporaries are destroyed at the end of the full expression containing the call to operator+. The temporary T3 bound to the reference cr is destroyed at the end of cr’s lifetime, that is, at the end of the program. In addition, the order in which T3 is destroyed takes into account the destruction order of other objects with static storage duration. That is, because obj1 is constructed before T3, and T3 is constructed before obj2, it is guaranteed that obj2 is destroyed before T3, and that T3 is destroyed before obj1. ]
总结:
第二种情况是,当一个引用绑定临时对象时,只有当引用或临时对象超出作用域时析构(因为当临时对象被析构后,指向该临时对象的引用也就自然没用了)
例如
{
X a,b;
cout << "----------"<<endl;
X &c=a+b; // 临时对象因被引用,故而延期析构
cout << "----------"<<endl;
return 0; // 此时临时对象析构
}
另,发现对于指针,则完全没有什么因临时对象被“引用”而延长生命期这一说法
{
int i;
public:
T(){ i = 99; }
void show(){ cout << i<<endl; }
} ;
int main()
{
T *p;
cout << "========="<<endl;
p=&f(); // f函数一旦调用完,临时对象就被析构
(*p).show(); // 输出垃圾值
cout << "========="<<endl;
cout << "return"<<endl;
}