【问题标题】:When is the destructor of the temporary called什么时候调用临时的析构函数
【发布时间】:2015-03-31 18:23:30
【问题描述】:

我想知道 C++03 和 C++11 何时调用 temporay 的析构函数

假设我有以下情况

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

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

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

【问题讨论】:

  • 这里的C++11和C++03中的临时对象被销毁的方式完全一样。您的示例中唯一的区别是在 C++03 中调用了 foo(const foo&),而在 C++11 中有时调用了 foo(foo&&)

标签: c++ c++11


【解决方案1】:

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 中所述内容的需要。

【讨论】:

    【解决方案2】:

    我想知道什么时候调用 temporay 的析构函数 C++03 和 C++11

    R-Value(临时)的析构函数在表达式的末尾被调用。

    给出你的代码:

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

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

    调用 "foo f="... 导致调用 foo 的复制构造函数。之后表达式结束,导致返回的对象(临时)被破坏。对象“f”的析构函数在 doSomething 结束时超出范围时被调用。

    【讨论】:

      猜你喜欢
      • 2019-04-07
      • 2015-09-23
      • 2021-02-16
      • 2020-11-05
      • 2018-05-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-04
      相关资源
      最近更新 更多