【问题标题】:C++ Why is Destructor called when I pass a Class Pointer?C++ 为什么在传递类指针时调用析构函数?
【发布时间】:2012-07-22 10:34:30
【问题描述】:
int main(){
   //Node is some template class
   Node<int>* head = new Node<int>[5];

   for(int ii = 0; ii < 5; ii++)
   {
      head[ii].set_Data(ii);
      head[ii].set_Link(head + (ii + 1));
      if(ii == 4)
      {
        head[ii].set_Link(NULL);
      }
   }
   delete [] head;
 }


template<typename T>
void Node<T>::set_Link(Node* Node_Address)
{
    Link = Node_Address;
}


template<typename T>
Node<T>::~Node()
{
    delete Link;
    cout << "Destructor" << endl;
}

我现在正在学习链表。我不明白为什么我的析构函数被调用 15 次而 cout 语句被打印 15 次。 如果我摆脱声明

head[ii].set_Link(head + (ii + 1));

析构函数只被调用了 5 次,这是有道理的,因为创建了 5 个类。 为什么在我使用成员函数 set_Link() 时调用析构函数,而我只传递一个指针,而不是一个类。甚至没有调用复制构造函数。感谢您的帮助!

【问题讨论】:

  • "为什么我使用成员函数set_Link()时调用了析构函数。" - 它没有被调用。你已经在做一些跟踪消息,添加更多。我不知道你怎么没注意到这一点。
  • 请发布一个完整但最小的程序来演示此行为。否则,我们只能猜测,这对您没有帮助。
  • 请在您描述的任何一种情况下发布确切的输出。 set_Data的代码是什么?

标签: c++ class memory pointers destructor


【解决方案1】:

你这里有 UB。析构函数被多次调用。 delete [] head; 调用数组中每个对象的析构函数。析构函数又通过delete Link;调用链接对象的析构函数。

总共调用了 5 + 4 + 3 + 2 + 1 = 15 次析构函数。主要是在已经销毁的对象上。

通常,您不会为链表的元素创建数组。相反,创建这样的列表:

Node<int>* head = new Node<int>(); 
Node<int>* node = head;
for(int ii = 0; ii < 5; ii++) 
{ 
  node->set_Data(ii); 
  if(ii == 4) 
  { 
    node.set_Link(NULL); 
  }
  else
  {
    Node<int>* next = new Node<int>();
    node->set_Link(next);
    node = next;
  }
} 
delete head; 

【讨论】:

  • 谢谢。我按照 Karoly 的建议在“删除链接”之前添加了 cout 语句,并且消息就像你预测的那样会调用析构函数。我不会猜到这种行为。我会记得在创建新列表时,是否有特殊原因导致数组不利于初始化列表?
  • @JimmyWong:当您需要能够在随机位置添加/删除节点时,您可以使用链表。如果元素存储在数组中,这并不容易。
  • @cojocar UB = 未定义行为stackoverflow.com/questions/2766731/…
【解决方案2】:

在链表节点析构函数中,您不想删除指向的下一个节点。这将级联删除所有尾节点。您可以通过先将指针设置为 NULL 来防止它发生,但这只是一个可维护性的噩梦,并且会产生很多像这样的细微错误。

注意:“为什么在我使用成员函数 set_Link() 时调用了析构函数” - 它没有被调用,通过添加一些额外的跟踪消息很容易验证这一点。所有的析构函数调用都源自那个delete [] 调用。

【讨论】:

    【解决方案3】:

    五个节点的完整数组是通过new创建的,没关系。但是您传递给set_Link() 的指针指向此内存块内的某个位置,因此(a)当您的析构函数调用delete Link; 时,堆管理器不知道如何处理它们,并且(b)即使它知道,它们被删除多次,因为你的五个对象要互相删除。

    注意:你只需要delete你通过new获得的东西。

    【讨论】:

    • 谢谢,注意删除,我误读了教科书上的一些内容。你是对的,删除“删除链接”,程序现在的行为更加可预测,析构函数现在只调用了 5 次。
    猜你喜欢
    • 1970-01-01
    • 2014-04-22
    • 1970-01-01
    • 1970-01-01
    • 2019-10-28
    • 1970-01-01
    • 2020-09-06
    • 2014-11-25
    • 2013-06-20
    相关资源
    最近更新 更多