SortListClass& SortListClass::operator=(const SortListClass& rhs)
{
// Similar to Copy Constructor, except
// - Avoid self-assignments such as “X = X;”
// - Delete existing this-instance content before
// making this-instance a copy of the rhs instance
if (this == &rhs)
{ return *this; }
delete[] this;
head->item = rhs.head->item;
}
private:
struct SortListNode
{
SortListItemType item;
SortListNode *next;
};
int size; // number of items in list
SortListNode *head; // pointer to linked list of items
SortListNode *last;
SortListNode *ptrTo(int position) const;
// Returns a pointer to the node at position (1 .. k) in list
};
Line 9: deletethis[];
Is extremely suspect in that it assumes that *this was allocated with a new[] expression. If it is not, your code will exhibits undefined behavior. It is generally a good idea to avoid committing suicide (delete this, or explicitly calling your own destructor), although there are cases when it makes sense.
So:
You should release the memory resources owned by *this, not *this itself. Those are the linked-list nodes, implying you should walk the list and delete each node individually. If such code exists in the destructor (it should), you can simply call it: this->~SortListClass();
And then reuse storage, copy-constructing a new object in your place from the right-hand side: new (this) SortListClass(rhs);
This forwards the work of copying over to the copy-constructor. You should post your copy-constructor.
Note:
In modern C++ it is relatively unusual that you need to implement the functions described in the Rule of Three (or five, if you prefer). The Rule of Three says that if you implement one of the copy-constructor, copy-assignment operator, or destructor, you should implement them all.
The purpose of following the Rule of Three is to support RAII. The purpose of RAII is to reduce the risk of resource leaks, even in the presence of exceptions.
The design I just discussed is an indication of poor (especially exception-unsafe) design. In fact, even the two lines of code I have posted are terribly broken: the copy-construction can fail -- if that happens, you're in trouble, since your data was just destroyed.
The alternative to this awfully ugly code above is the well-known copy-and-swap idiom. Post your copy constructor and I'll go into more detail.
Okay, my first example did not make sense. I am trying to do a deep copy. This seems to work:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
// assignment operator: Make DEEP copy
SortListClass& SortListClass::operator=(const SortListClass& rhs)
{
// TODO
// Similar to Copy Constructor, except
// - Avoid self-assignments such as “X = X;”
// - Delete existing this-instance content before
// making this-instance a copy of the rhs instance
if (this != &rhs)
{
delete[] head;
head = rhs.head;
}
return *this;
}
my header file:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
private:
struct SortListNode
{
SortListItemType item;
SortListNode *next;
};
int size; // number of items in list
SortListNode *head; // pointer to linked list of items
SortListNode *last;
SortListNode *ptrTo(int position) const;
// Returns a pointer to the node at position (1 .. k) in list
};
Now the following seems to copy and print correct:
Okay, I'm a little confused. I'm a little confused on the left side what is suppose to be deleted? Is it item that should receive delete [] item, but that's not a pointer that can be deleted, so shouldn't it by delete [] head;?
Do I need to first create a new heap ?
The below works.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
SortListClass& SortListClass::operator=(const SortListClass& rhs)
{
// TODO
// Similar to Copy Constructor, except
// - Avoid self-assignments such as “X = X;”
// - Delete existing this-instance content before
// making this-instance a copy of the rhs instance
SortListClass copyme;
if (this != &rhs)
{
delete[] copyme.head;
copyme.head = rhs.head;
}
return *this;
}
newlist.operator=(newlist3);
Each newlist and newlist3 seem to occupy different areas of memories, since newlist.remove(1) does not affect newlist3.remove(1);
still a little confused on what to delete. Do I need to create a new item on the heap
For copy assignment of a linked list, you really should only delete the nodes at the end of your list if the list in rhs is shorter than yours, and create new nodes at the end of your list if the list in rhs is longer than yours.. or just do as mbozzi suggested and reuse your destructor (not by calling any sort of delete!) and your copy constructor, either directly or via copy-and-swap - it's just three lines of code either way.
What should my delete [] function look like? I am still not sure what to delete, but the assignment says "// - Delete existing this-instance content before
// making this-instance a copy of the rhs instance "
Your class owns a pointer to some memory somewhere (i.e., head).
This memory is a "resource".
When you simply copy the pointer, both objects get a pointer to the exact same resource. That's a shallow copy. A deep copy creates a copy of the resource.
Take the left-hand-side's resource -- e.g., head and everything head owns nodes (next, and so on), and delete them all. Freeing everything the list owns is the job of the destructor, so this code belongs there.
Something like
1 2 3 4 5 6 7
~List() { // destroy every node.
// Assumes each node was allocated with a independent new-expression
for (Node *it = head, *next; it; it = next)
next = it->next;
delete it;
}
}
Then you can call your destructor to release the stuff you own, and use the copy-constructor to replace your stuff with deep copies of the right-hand-side's stuff.
Assuming a correct copy-constructor, this will leave you with a complete copy-assignment operator that looks like this:
1 2 3 4 5 6 7
SortListClass& operator=(SortListClass const& rhs) {
if (std::addressof(rhs) == this) return *this; // careful for self-assignment
this->~SortListClass();
new (this) SortListClass(rhs);
// Edit: need to return something :)
return *this
}
This is still subject to the same issues that I mentioned above (it's exception-unsafe), but it's a start.
OP: I've tried to implement a combination of max and cubbi's suggestions for the copy ctor and copy assignment particularly (a) making deep copies through the copy ctor; (b) calling the dtor within copy assignment and (c) using the copy-swap idiom: