简体   繁体   English

单链接列表中的重载operator =

[英]Overloading operator= in a singly linked list

I'm currently having a problem copying the contents from one list to another. 我目前在将内容从一个列表复制到另一个列表时遇到问题。 The values all appear as 0 when compiled. 编译时,所有值均显示为0。 I thought that there might be something wrong when overloading the assignment operator as the copy constructor is using its code. 我认为,当复制构造函数正在使用其代码时,重载赋值运算符可能会出问题。

Copy Constructor 复制构造函数

ListOfDoubles::ListOfDoubles(const ListOfDoubles&e):head(NULL) {
if (this != &e) {
    *this = e;
}
}

Overloaded operator= 重载运算符=

const ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles 
&doubleslist)
{
DoubleListNode *cpyPtr = NULL;
DoubleListNode* orgPtr = doubleslist.head;

if (this != &doubleslist)
{
    while (head != NULL)
    {
        ListOfDoubles::~ListOfDoubles();
    }

    while (orgPtr != NULL)
    {
        if (head == NULL)
        {
            head = cpyPtr = new DoubleListNode(orgPtr->data);

        }
        else
        {
            cpyPtr->next = new DoubleListNode(orgPtr->data);
            cpyPtr = cpyPtr->next;
        }
        orgPtr = orgPtr->next;
    }
}
return *this;
}

General-purpose copy logic looks something like: 通用复制逻辑如下所示:

DoubleListNode * from = source.head; // copying from
DoubleListNode ** to = &head; // pointer to where we want to copy to
while (from != nullptr) // keep going until end of list. You did mark 
                        // the end of the list, didn't you?
{
    *to = new node(*from); //copy construct a new node around from and store it at to
    to = &(*to)->next; // advance to
    from = from.next; // advance from
}
*to = nullptr; // all done. Terminate list.

The real magic is going on up here at the double pointer: DoubleListNode ** to By having a pointer to a pointer, we don't care whether we're pointing at head , another node's next or what have you. 真正的魔力在这里出现在双指针处: DoubleListNode ** to通过拥有一个指向指针的指针,我们不在乎我们是指向head ,另一个节点的next一个节点还是拥有什么。 It's just another node, so there are no special cases to cover. 它只是另一个节点,因此没有特殊情况需要讨论。

You can do the above in both the copy constructor and assignment operator, though you are better off not repeating yourself and putting it in a function called by the copy constructor and assignment operator. 您可以在复制构造函数和赋值运算符中执行上述操作,尽管最好不要重复自己,并将其放入复制构造函数和赋值运算符调用的函数中。 Note that there are different assumptions about pre-existing data in the copy constructor (eg, list will be empty) and the assignment operator (eg, list may not be empty, so clear it and free all of the nodes before you begin) that need to be taken into account. 请注意,对于复制构造函数中的现有数据(例如,列表将为空)和赋值运算符(例如,列表可能不为空,因此请清除它并在开始之前释放所有节点)有不同的假设:需要考虑在内。

The primary alternative, as discussed in the comments above, is to use the Copy and Swap Idiom . 如上面的评论所述,主要的替代方法是使用Copy and Swap Idiom For this, the above copy loop only exists in the copy constructor. 为此,上述复制循环仅存在于复制构造函数中。

The input parameter of a copy constructor will never be the object being constructed, so checking for this != &e in the copy constructor is redundant. 复制构造函数的输入参数永远不会是要构造的对象,因此在复制构造函数中检查this != &e是多余的。

Also, manually calling a destructor directly is illegal unless the memory was allocated with placement-new , which you are not using. 此外,除非使用不使用的placement-new分配内存,否则直接手动调用析构函数是非法的。 You need to use delete to destroy your node instances. 您需要使用delete销毁您的节点实例。

Typically, you shouldn't implement the copy constructor in terms of operator= , you should do it the other way around. 通常,不应以operator=形式实现复制构造函数,而应采用其他方法。 Let the copy constructor do its job of copying the source values, and then have operator= make a copy of the source list and take ownership of the copied data. 让复制构造函数完成复制源值的工作,然后让operator=复制源列表并获得复制数据的所有权。 This is commonly known as the "copy and swap" idiom. 这通常称为“复制和交换”习惯用法。

Try this instead: 尝试以下方法:

ListOfDoubles::ListOfDoubles()
    : head(NULL)
{
}

ListOfDoubles::ListOfDoubles(const ListOfDoubles &e)
    : head(NULL)
{
    DoubleListNode *cpyPtr = NULL;
    DoubleListNode *prevPtr = NULL;
    DoubleListNode *orgPtr = e.head;

    while (orgPtr)
    {
        cpyPtr = new DoubleListNode(orgPtr->data);

        if (!head)
            head = cpyPtr;

        if (prevPtr)
            prevPtr->next = cpyPtr;
        prevPtr = cpyPtr;

        orgPtr = orgPtr->next;
    }

    /* alternatively:

    DoubleListNode **cpyPtr = &head;
    DoubleListNode *orgPtr = e.head;

    while (orgPtr)
    {
        *cpyPtr = new DoubleListNode(orgPtr->data);
        cpyPtr = &((*cpyPtr)->next);    
        orgPtr = orgPtr->next;
    }

    *cpyPtr = NULL;
    */
}

ListOfDoubles::~ListOfDoubles()
{
    DoubleListNode *orgPtr = head;
    DoubleListNode *nextPtr;

    while (orgPtr)
    {
        nextPtr = orgPtr->next;
        delete orgPtr;
        orgPtr = nextPtr;
    }
}

ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles &doubleslist)
{
    if (this != &doubleslist)
    {
        ListOfDouble tmp(doubleslist);
        std::swap(head, tmp.head);
    }
    return *this;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM