【问题标题】:Passing by reference - why is this destructor being called?通过引用传递——为什么要调用这个析构函数?
【发布时间】:2018-10-26 21:10:05
【问题描述】:

我找不到(在关于析构函数调用主题的许多问题中)任何与我的情况完全相同的问题。

为什么传递的参数是引用时调用析构函数?我将 cmets(主要在 main 中)放在我认为执行输出的代码行下。

struct X { // simple test class
   int val;

   void out(const std::string& s, int nv)
   {
      std::cerr << this << "–>" << s << ": " << val << " (" << nv << ")\n";
   }

   // default constructor
   X() { 
      out("X()", 0); 
      val = 0; 
   } 

   X(int v) { 
      val = v; 
      out("X(int)", v); 
   }

   // copy constructor
   X(const X& x) {
      val = x.val; 
      out("X(X&) ", x.val); 
   } 

   // copy assignment
   X& operator=(const X& a)
   {
      out("X::operator=()", a.val); 
      val = a.val; 
      return *this;
   }

   // Destructor
   ~X() { 
      out("~X()", 0); 
   }
};

X glob(2); // a global variable
// Output Line 1: X(int): 2 (2)

X copy(X a) { 
   return a; 
}

main功能:

    int main()
{
   X loc{ 4 }; // local variable
      // Output Line 2: X(int): 4 (4)
      // ^from X(int v) function
   X loc2{ loc }; // copy construction
      // Output Line 3: X(X&) : 4 (4)
      // ^from X(const X& x) function
   loc = X{ 5 }; // copy assignment 
      // Output Line 4: X(int): 5 (5)
      // ^from X(int v) function
      // Output Line 5: X::operator=(): 4 (5)
      // ^from the '=' operator overload
      // Output Line 6: ~X(): 5 (0) - ???
   loc2 = copy(loc); // call by value and return 
      // Or does Output Line 6 result from here?
   .
   .
   .
}

1) 这个析构函数被调用是因为loc = X{ 5 }; // copy assignment 还是后面的行:loc2 = copy(loc); // call by value and return

2) 为什么要调用它?根据我的阅读,只有在以下情况下才会调用析构函数:

a) names go out of scope
b) program terminates
c) "delete" is used on a pointer to an object

我知道它不是“b”或“c”,所以它必须是因为某些东西超出了范围。但我不认为复制分配函数超出范围的引用会这样做。

【问题讨论】:

  • 你的理解有问题。当对象的生命周期结束时,即当对象“死亡”时,就会调用析构函数。超出范围的对象和delete 就是两种这样的情况。 X{ 5 } 是一个临时的,它的生命周期在语句的末尾结束,分号。
  • X{5} 没有涉及范围,因为它没有名称。名称有作用域,对象有生命周期。

标签: c++ destructor


【解决方案1】:

您可以看到析构函数在复制分配发生后不久被调用。复制分配完成后,临时的(x{5})被销毁。

来自标准的析构函数部分:

15.4 析构函数
...
12.隐式调用析构函数
(12.1) — 对于在程序终止时具有静态存储持续时间的构造对象,
(12.2) — 对于在线程退出时具有线程存储持续时间的构造对象,
(12.3) — 对于在其中创建对象的块退出时具有自动存储持续时间的构造对象,
(12.4) — 对于其生命周期结束时构造的临时对象。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-24
    • 1970-01-01
    • 2011-06-11
    • 1970-01-01
    • 2015-10-08
    • 2021-09-20
    • 1970-01-01
    • 2014-04-22
    相关资源
    最近更新 更多