【问题标题】:Assignment Operator not working properly in circular doubly linked list赋值运算符在循环双向链表中无法正常工作
【发布时间】:2020-06-26 11:03:33
【问题描述】:

我正在做一个带有哨兵节点的双向链表,使双向链表成为一个循环列表(没有指向前后的头和尾指针,相反,头由 m_sentinel->m_next 和tail 由 m_sentinel->m_prev 引用)。下面是代码:

在 MyList.h 中:

template <typename T>
class Node
{
    public:
        T m_element;

        Node<T> *m_prev;
        Node<T> *m_next;

        // Helps make a dummy/sentinel/junk node
        Node(Node<T> *in_prev, Node<T> *in_next): 
            m_prev(in_prev), m_next(in_next){}

        Node(const T &x, Node<T> *in_prev, Node<T> *in_next): 
            m_element(x), m_prev(in_prev), m_next(in_next){}
};

template <typename T>
class MyList
{
    private:
        Node<T> *m_sentinel = nullptr;

        int m_size;

    public:
        MyList();

        ~MyList();

        MyList<T> & operator=(const MyList<T> &source);

        void clear();

        void push_back(const T &x);

在 MyList.hpp 中:

template <typename T>
MyList<T>::MyList()
{
  m_size = 0;
  m_sentinel = new Node<T>(NULL, NULL);
}

template <typename T>
MyList<T>::~MyList()
{
  clear();

  m_size = 0;
}

template <typename T>
MyList<T> & MyList<T>::operator=(const MyList<T> &source)
{
  if(this == &source)
  {
    return *this;
  }
  while(source.m_sentinel->m_next != source.m_sentinel)
  {
    Node<T> *temp = source.m_sentinel->m_next;
    push_back(temp->m_element);
    source.m_sentinel->m_next = temp->m_next;
  }

  return *this;
}

template <typename T>
void MyList<T>::clear()
{
  if(m_sentinel->m_prev == NULL && m_sentinel->m_next == NULL)
  {
    delete m_sentinel;
  }
  else
  {
    int k = size();
    for(int i = 0; i < k; i++)
    {
      pop_back();
    }
    delete m_sentinel;
  }
}

template <typename T>
void MyList<T>::push_back(const T &x)
{
  Node<T> *newNode;
  newNode = new Node<T>(x, NULL, NULL);
  if(m_sentinel->m_prev == NULL && m_sentinel->m_next == NULL)
  {
    newNode->m_prev = m_sentinel;
    newNode->m_next = m_sentinel;
    m_sentinel->m_prev = newNode;
    m_sentinel->m_next = newNode;
  }
  else
  {
    newNode->m_next = m_sentinel;
    newNode->m_prev = m_sentinel->m_prev;
    Node<T> *temp = newNode->m_prev;
    m_sentinel->m_prev = newNode;
    temp->m_next = m_sentinel->m_prev;
  }
  m_size++;
}

在 main.cpp 中:

#include "MyList.h"

int main()
{
    MyList<int> x;
    x.push_front(1);
    x.push_front(2);
    x.push_front(3);
    x.push_front(4);
    x.push_front(5);
    x.push_front(6);
    x.push_front(7);
    MyList<int> p;
    p = x; 

    // Below just outputs each linked list
    int j = 0;
    int m = x.size();
    cout << endl << endl;
    for(auto i = 0; i < m; i++)
    {
        cout << x.front() << endl;
        x.pop_front();
        j++;
    }
    cout << endl << endl;
    j = 0;
    m = p.size();
    for(auto i = 0; i < m; i++)
    {
        cout << p.front() << endl;
        p.pop_front();
        j++;
    }
    cout << endl << endl;

运行此代码时,x 确实被成功复制到 p。输出 p 时,给出以下输出:7 6 5 4 3 2 1,但输出 x 时,给出以下输出:-19823746 ... 这只是垃圾内存值(这告诉我 x 显然正在改变,但 p 成功获取 x 的内容)。我不知道它为什么会改变;我正在寻找赋值运算符的修复/解决方案,因为它无法正常工作。

【问题讨论】:

  • 您的用户定义的复制构造函数在哪里?即使你让赋值运算符工作,你的类仍然被破坏,并且通过在 main 函数中执行 MyList&lt;int&gt; p = x; 很容易破坏。阅读the rule of three
  • 我打算在赋值运算符之后处理复制构造函数 - 坏主意?不过我会检查那个链接,谢谢!
  • 最好的方法是先处理复制构造函数和析构函数。不理会赋值运算符。然后,当您可以使复制构造函数和析构函数正常工作时,赋值运算符大约需要两分钟才能使用copy / swap 成语正确编码。
  • {MyList&lt;T&gt; t = source; std::swap(t.m_size, m_size); std::swap(t.m_sentinel, m_sentinel); return *this;} -- 信不信由你,那将是赋值运算符如果您首先编写了复制构造函数和析构函数。
  • 然后自己交换物品。这就是std::swap 所做的一切。请阅读有关复制和交换的链接。您所做的就是将临时变量内容换成当前内容,然后让临时变量消失。

标签: c++ linked-list operator-overloading doubly-linked-list assignment-operator


【解决方案1】:

在您的 MyList::operator= 内部,您应该使用新变量而不是 source.m_sentinel 成员本身进行迭代。这会更改实际列表,实际上是在删除节点。

改用这个:

Node<T>* current = source.m_sentinel;
while (current->m_next != source.m_sentinel) {
  Node<T>* temp = current->m_next;
  push_back(temp->m_element);
  current = temp;
}

【讨论】:

  • 我试过这样做,但我得到了错误:'terminate call after throwing an isnttance of 'St9bad_alloc' what(): std::bad_alloc Aborted (core dumped)
  • 为了清楚起见,这里是当前函数:``template MyList & MyList::operator=(const MyList &source) { if(this == &source) { 返回 this; } 节点 当前 = source.m_sentinel; while(current->m_next != source.m_sentinel) { Node* temp = current->m_next; push_back(temp->m_element);当前 = temp->m_next; } 返回 *this; }` ```
  • @bmcisme 使用您的调试器并跟踪错误的来源。我写的代码看起来是正确的,所以它可能不是来自我的示例......
  • @bmcisme 尝试将current = temp-&gt;m_next 更改为current = temp(来自我的示例),看看会发生什么。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-20
  • 1970-01-01
  • 1970-01-01
  • 2015-11-27
  • 2015-04-25
  • 1970-01-01
相关资源
最近更新 更多