简体   繁体   中英

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. 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. 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 . 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.

Also, manually calling a destructor directly is illegal unless the memory was allocated with placement-new , which you are not using. You need to use delete to destroy your node instances.

Typically, you shouldn't implement the copy constructor in terms of operator= , you should do it the other way around. 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. 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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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