C++ 为什么当我传递类指针时调用析构函数

C++ Why is Destructor called when I pass a Class Pointer?

本文关键字:指针 调用 析构函数 为什么 C++      更新时间:2023-10-16
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(( 时调用析构函数,当我只传递指针而不是类时。甚至没有调用复制构造函数。感谢您的任何帮助!

这里有 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; 

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

注意:"为什么当我使用成员函数 set_Link((" 时调用析构函数" - 它不会被调用,并且通过添加一些额外的跟踪消息来验证这一点非常容易。所有析构函数调用都源自该delete []调用。

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

请注意:您只需要delete通过new获得的东西