双重连锁名单三巨头

时间:2016-10-24 16:18:46

标签: c++ destructor copy-constructor doubly-linked-list assignment-operator

我在尝试让我的复制构造函数,析构函数和赋值运算符为双链表工作时遇到了很多麻烦。 我有一个名为dlist的类和一个节点类。 Node类包含next和previous的私有节点以及数据字段。我真的被卡住了,我不能为我的生活理解如何让这些工作。如果有人甚至只是指出什么是错的。有时候我会遇到一个段错误,有时我会得到一个回溯,这取决于我在三巨头中的变化。

//Destructor
template<class T>
dlist<T>::~dlist(){
    node<T> *rmptr = head;
    while(head != NULL && head != tail){
        head = head -> next();
        delete rmptr;
    }
}

//Copy Constructor
template <class T>
dlist<T>::dlist(const dlist<T>& other)
{
    if(other.head == NULL){
        head = new node<T>;
        tail -> set_next(head);
    }
    else{
        head = new node<T>(other.head -> data());
        tail = new node<T>;
        head -> set_next(tail);
        tail -> set_previous(head);
        node<T> *source = other.head -> next();
        node<T> *destination = head;
        while(source != NULL && source != other.tail){
            tail -> set_next(new node<T>);
            destination -> set_next(tail);
            tail -> set_data(source -> data());
            tail = tail -> next();
            source = source -> next();
        }
    }

}

//Assignment Operator
template<class T>
dlist<T>& dlist<T>::operator =(const dlist& other){

    if(this == &other){
        return *this;
    }
    node<T> * rmptr;
    while(head != NULL){
        rmptr = head;
        head = head -> next();
        delete rmptr;
    }
    head = tail = NULL;

    node<T> *source, *destination;
    if(other.head != NULL){
        head = new node<T>(other.head -> data());
        tail = new node<T>;
        head -> set_next(tail);
        tail -> set_previous(head);
        node<T> *source = other.head -> next();
        node<T> *destination = head;
        while(source != NULL && source != other.tail){
            tail -> set_next(new node<T>);
            destination -> set_next(tail);
            tail -> set_data(source -> data());
            tail = tail -> next();
            source = source -> next();
        }
    }

    return *this;
}

1 个答案:

答案 0 :(得分:0)

这个副本/赋值/构造函数/析构函数模式是经典的(至少按照我的标准:))

  • 首先,您必须将headtail设置为NULL(或nullptr),以避免在刚刚创建和未使用对象时出现段错误。这避免了析构函数读取未初始化的headNULL阻止析构函数执行有害的操作
  • 第二步:创建一个由析构函数(当然)使用的destroy实用程序方法,也可以通过赋值运算符来释放已分配的对象(否则会导致内存泄漏)。无需复制/粘贴相同的代码。我首先假设您的删除代码没问题,但事实并非如此。

destroy看起来像这样(修复了WhozCraig评论的帮助):

template<class T>
void dlist<T>::destroy()
{
    node<T> *rmptr;
    while(head != NULL && head != tail){
        rmptr = head;
        head = head -> next();
        delete rmptr;

    }
    head = tail = NULL; // set head to NULL again

}

析构函数看起来像这样:

template<class T>
dlist<T>::~dlist(){
   destroy();
} 
  • 第三个创建一个由复制构造函数和赋值运算符使用的copy实用程序方法(它们共享许多相同的代码,无需复制/粘贴)

copy方法如下所示:

template <class T>
void dlist<T>::copy(const dlist<T>& other)
{
    if(other.head == NULL){
        head = new node<T>;
        tail -> set_next(head);
    }
    else{
        head = new node<T>(other.head -> data());
        tail = new node<T>;
        head -> set_next(tail);
        tail -> set_previous(head);
        node<T> *source = other.head -> next();
        node<T> *destination = head;
        while(source != NULL && source != other.tail){
            tail -> set_next(new node<T>);
            destination -> set_next(tail);
            tail -> set_data(source -> data());
            tail = tail -> next();
            source = source -> next();
        }
    }

}

您现在可以实现复制构造函数&amp;赋值运算符非常简单:

template<class T>
dlist<T>::dlist(const dlist<T>& other)
{
    copy(other);
}

//Assignment Operator
template<class T>
dlist<T>& dlist<T>::operator =(const dlist& other){

    if(this == &other){
        return *this;
    }
    destroy();
    copy(other);

    return *this;
}

在将对象分配到另一个对象时,您不会有任何内存泄漏问题。#34;完全&#34; (也称为已分配)对象,因为新对象headtailNULL,您不会因释放未分配区域而获得段错误。

我为回答&#34;超越&#34;而道歉问题,但这种模式是非常有用的,尝试编写像这样的低级别类的未经训练的编码员总是偶然发现内存泄漏/崩溃/复制粘贴障碍。