临时对象的析构函数何时被调用?

8

我希望了解在C++03和C++11中,临时对象的析构函数何时被调用。

假设我有以下情况:

foo method()
{
   foo f;
   ......
   ......
   return foo;
}

void doSomething()
{
   foo f = method();
   ....
}

假设我正在使用标志-fno-elide-constructors,因为我想理解临时对象的析构函数何时被调用的理论知识。因此,在上述C++03代码中,当method()完成后,使用其复制构造函数创建了foo的副本。之后,在语句foo f = method()中再次调用了foo的复制构造函数。在这种情况下,对于C++03,这个由method传递的临时对象的析构函数是在何时调用的呢?它是在doSomething()作用域结束时调用吗? 现在我想将相同的情况应用于涉及移动语义的C++11。在C++11的情况下,当method返回时,会创建foo的副本。然后,在调用foo f = method()时,将调用foo的移动构造函数。那么,在C++11的情况下,从method()返回的临时对象的析构函数是在何时调用的?

7
在这里,C++11和C++03中的临时对象被以完全相同的方式销毁。你示例中唯一的区别在于,在C++03中调用了foo(const foo&),而在C++11中有时会调用foo(foo&&) - Mooing Duck
2个回答

11

我想知道在C++03和C++11中,临时对象的析构函数何时被调用。

R-Value(临时对象)的析构函数会在表达式结束时被调用。

请提供你的代码:

foo method()
{
   foo f;
   ......
   ......
   return foo;
}

void doSomething()
{
   foo f = method();
   ....
}

method() 创建一个对象。当该对象超出范围(在方法末尾时),析构函数将被调用(如果没有优化的情况下)。

调用 "foo f="... 会导致复制构造函数 foo 被调用。之后表达式结束,致使返回的对象(临时对象)被销毁。当对象 "f" 在 doSomething 的结尾处超出范围时,其析构函数被调用。


10

C++03

实现引入临时对象时,如果该类具有非平凡构造函数(12.1),则它应确保为该临时对象调用构造函数。同样,对于具有非平凡析构函数(12.4)的临时对象,应调用其析构函数。无论该评估是否以抛出异常结束,“临时对象在包含它们创建点的(词法)完整表达式(1.9)评估完成时被销毁”(最后一步)。 (12.2/3)
除了完整表达式的结尾外,存在两种上下文环境会导致临时对象在不同的时间点被销毁。第一个上下文环境是当表达式作为初始化器出现在定义对象的声明符中时。在这种情况下,“保存表达式结果的临时对象必须持续到对象的初始化完成”。对象是从临时对象的副本中初始化;在此过程中,实现可以调用复制构造函数多次;临时对象在被复制后被销毁,在初始化完成之前或同时进行。如果许多临时对象是通过评估初始化器而创建的,则在它们建立完成的相反顺序下销毁这些临时对象。(12.2/4)
因此,method() 的临时结果在初始化结束时被销毁。

C++11

当实现引入具有非平凡构造函数(12.1、12.8)的类的临时对象时,它应确保为该临时对象调用构造函数。同样,对于具有非平凡析构函数(12.4)的临时对象应调用其析构函数。无论该评估是否以抛出异常结束,“临时对象在包含它们创建点的(词法)完整表达式(1.9)评估完成时被销毁”(最后一步)。这是真实的,即使该评估以抛出异常而结束。销毁临时对象的值计算和副作用仅与完整表达式相关,而不与任何特定子表达式相关。(12.2/3)
C++11没有明确说明用作初始化器的临时对象会持续到初始化完成。相反,在1.9/10中有一个示例:
struct S {
  S(int i): I(i) { }
  int& v() { return I; }
private:
  int I;
};

S s1(1); // full-expression is call of S::S(int)
S s2 = 2; // full-expression is call of S::S(int)

void f() {
  if (S(3).v()) // full-expression includes lvalue-to-rvalue and
                // int to bool conversions, performed before
                // temporary is deleted at end of full-expression    
  { }
}

这很可能是为了澄清一个带有非平凡初始化的对象被初始化时,会有一个包含其构造函数调用的完整表达式。这消除了在C++03中需要明确说明的12.2/4中所述内容的需要。

示例结束]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接