【问题标题】:C++ Destructor deleting stuff(objects, pointers?) too soonC ++析构函数删除东西(对象,指针?)太快了
【发布时间】:2013-12-21 18:51:23
【问题描述】:

我有一个创建节点并将它们插入双向链表的分配。其中一个规范是包含一个析构函数。由于某种原因,当我在 main 中调用 addSortedList() 时,我的析构函数似乎正在删除对象或指针或两者。如果我取出析构函数,程序运行得很好,当调用 addSortedList() 时程序会崩溃。今天我什至花了一些时间和我的导师在一起,他说我的析构函数看起来很好,但不知道是什么导致了问题。有人可以向我解释为什么会这样吗?

#include <iostream>

using namespace std;

template <typename T>
class DoublyLinkedList;

template <typename T>
class Node
{
  friend class DoublyLinkedList<T>;

  public:
    Node();
    Node(const T& data, Node<T> *next, Node<T> *prev);

  private:
    T data;
    Node<T> *next;
    Node<T> *prev;
}; // end class Node

//*******************************************************************

// Create a header node for an empty linked list.

template <typename T>
Node<T>::Node()
{
  next = this;
  prev = this;
}

//*******************************************************************

// Create a regular node to be inserted into a linked list

template <typename T>
Node<T>::Node(const T& data, Node<T> *next, Node<T> *prev)
{
  this->data = data;
  this->next = next;
  this->prev = prev;
}

//*******************************************************************

template <typename T>
class DoublyLinkedList
{
  public:
    DoublyLinkedList();
    DoublyLinkedList(const T arr[], int arrSize);
    ~DoublyLinkedList();

    void insert(Node<T> *insertionPoint, const T& data);
    void display();
    DoublyLinkedList<T> addSortedList(const DoublyLinkedList<T>& list2);

  private:
    Node<T> *header;    // pointer to header node (header points to 
                        // front and back of list)
    int size;           // number of data nodes in list
}; // end class DoublyLinkedList

//*******************************************************************

// Default constructor creates only a header node

template <typename T>
DoublyLinkedList<T>::DoublyLinkedList()       
{
  header = new Node<T>();
  size = 0;
} // end constructor

//*******************************************************************

// Constructor takes in array and array size and creates a doubly
// linked list with a header node.

template <typename T>
DoublyLinkedList<T>::DoublyLinkedList(const T arr[], int arrSize)
{
  header = new Node<T>();
  size = arrSize;

  for (int i = size - 1; i > -1; i--)
  {
    insert(header->next, arr[i]);
  }
} // end constructor

//*******************************************************************

// Destructor to delete nodes after use.

template <typename T> 
DoublyLinkedList<T>::~DoublyLinkedList()
{
  Node<T> *oldFrontPointer; // pointer to node to be deleted
  Node<T> *newFrontPointer; // pointer to next node to be deleted

  oldFrontPointer = header->next;

  while (oldFrontPointer->next != header)
  {
    newFrontPointer = oldFrontPointer->next;
    delete oldFrontPointer;
    oldFrontPointer = newFrontPointer;
  }
  delete header;
} // end destructor


//*******************************************************************

// This function inserts a new node into a list

template <typename T>
void DoublyLinkedList<T>::insert(Node<T> *insertionPoint, const T& data)
{
  Node<T> *prevNodePtr;   // pointer to node that precedes insertionpoint
  Node<T> *newNodePtr;    // pointer to new node

  prevNodePtr = insertionPoint->prev;

  newNodePtr = new Node<T>(data, insertionPoint, prevNodePtr);
  size++;

  insertionPoint->prev = prevNodePtr->next = newNodePtr;
} // end insert

//*******************************************************************

// This function prints the node data from a list

template <typename T>
void DoublyLinkedList<T>::display()
{
  Node<T> *currentNodePtr = header->next;

  if (size == 0)
  {
    cout << "Empty linked list.";
  }
  else
  {
    while (currentNodePtr != header)
    {
      cout << currentNodePtr->data << " ";
      currentNodePtr = currentNodePtr->next;
    }
  }
  cout << "\n";
} // end display

//*******************************************************************

// This function merges the parameter list into the calling object
// list in sorted order assuming both lists are presorted.

template <typename T>
DoublyLinkedList<T> DoublyLinkedList<T>::
  addSortedList(const DoublyLinkedList<T>& list2)
{
  Node<T> *list1Pointer = this->header->next;
  Node<T> *list2Pointer = list2.header->next;

  while (list1Pointer != this->header && list2Pointer->next != list2.header)
  {
    // insert list 2 nodes if they are smaller than list 1 current node

    if (list1Pointer->data > list2Pointer->data)
    {
      insert(list1Pointer, list2Pointer->data);
      list2Pointer = list2Pointer->next;
    }

    // move list 1 pointer if list 1 current node is smaller than
    // list 2 current node

    else if (list1Pointer->data < list2Pointer->data)
    {
      list1Pointer = list1Pointer->next;
    }

    // insert list 2 nodes that are smaller than list 1 current node

    else if (list1Pointer->next == this->header)
    {
      insert(list1Pointer, list2Pointer->data);
      list2Pointer = list2Pointer->next;
    }
  }// end while

  // insert last list 2 nodes that are larger than last node in
  // list 1 at the end of the list

  while (list1Pointer->next == this->header && list2Pointer != list2.header)
  {
    list1Pointer = list1Pointer->next;
    insert(list1Pointer, list2Pointer->data);
    list2Pointer = list2Pointer->next;
  }  
  return *this;
} // end addSortedList

int main()
{
  int arrA[] = {20,80,100};
  int arrB[] = {10,30,60,100,110};
  int arrASize = sizeof(arrA)/sizeof(int);
  int arrBSize = sizeof(arrB)/sizeof(int);

  DoublyLinkedList<int> listA(arrA, arrASize);
  DoublyLinkedList<int> listB(arrB, arrBSize);
  DoublyLinkedList<int> listC;

  listC.display();
  listA.display();
  listB.display(); //extra
  listA.addSortedList(listB);
  listA.display();
  listB.display();
} // end main

【问题讨论】:

  • 你没有遵循三法则。
  • 克里斯所说的。有关更多信息,请阅读此处 (stackoverflow.com/questions/4172722/what-is-the-rule-of-three) - 您需要为您的类定义一个复制构造函数和赋值运算符。
  • 这与问题本身无关。在简单的情况下依赖默认的复制构造函数并没有错。
  • 当你的班级维护Node&lt;T&gt; *header; - 这正是三巨头的规则^^
  • 当您错误地或匆忙地在 15 个标头之外实施浅拷贝并忘记它时,此规则不会保护您免于假设深拷贝。规则很好,但不能代替问题分析。

标签: c++ templates destructor


【解决方案1】:

您正在从 addSortedList 返回一个值,因此您的意图显然是返回对 this 的引用。返回的复制值随后与原始对象共享内部列表指针,并立即使用它自己的析构函数将其删除。

替换这个:

template <typename T>
DoublyLinkedList<T> DoublyLinkedList<T>::
   addSortedList(const DoublyLinkedList<T>& list2)

用这个:

template <typename T>
DoublyLinkedList<T> &DoublyLinkedList<T>::
   addSortedList(const DoublyLinkedList<T>& list2)

【讨论】:

  • Visual Studio 2010 不允许我这样做。
  • 这个答案掩盖了课程中不遵循三巨头规则的更多主要问题^^请参阅问题本身的cmets中的链接
  • 问题是关于过早调用析构函数的原因,而不是编程哲学(属于programmers.sx或codereview.sx)。
  • @Ash 抱歉,我的回答有误。简而言之,你想在那里返回一个引用。
  • 好吧,这更有意义。现在可以用了,谢谢。 @Chris 我的讲师为我们提供了程序的规格,但他没有包含复制构造函数/复制赋值运算符。
猜你喜欢
  • 2012-12-22
  • 1970-01-01
  • 2015-01-10
  • 1970-01-01
  • 2014-12-30
  • 2021-04-04
  • 2021-07-25
  • 2018-01-03
  • 2013-10-01
相关资源
最近更新 更多