You have a lot of good questions there. Clearly, you read those last few posts carefully.
I will ty to answer the questions well.
Sorry about throwing the copy ctor and operator= in there without any detailed explanations. I thought you had bailed so I was trying to throw a quick wrap on things to make the list class safe to use.
Let' start with the issue of constructor styles. The issue of a copy of a list causing a crash can be seen starting there.
Our node structure:
1 2 3 4 5 6 7 8 9
|
struct node
{
int num;
string word;
node* link;
node(): link(NULL) {}// default ctor
// this ctor will be quite helpful
node( int Number, string Word, node* Link ): num(Number), word(Word), link(Link) {}
};
|
For our purposes here the (perhaps more common) notation for a ctor would work fine.
ie, For our structure here this ctor:
node( int Number, string Word, node* Link ): num(Number), word(Word), link(Link) {}
and this:
1 2 3 4 5 6
|
node( int Number, string Word, node* Link )
{
number = Number;
word = Word;
link = Link;
}
|
are equivalent. In the latter ctor, the data members number, word and link are first default constructed, then values are assigned to them in the body of the ctor.
This 2nd form cannot be used if any of the objects data members is lacking a no arg ctor itself.
How does this hint at the cause of our crash?
The issue of existence of default ctors has been raised.
As we know, if we provide a ctor definition at all it will override the default no arg ctor provided by the compiler.
If I eliminated the no-arg ctor from the node class:
node(): link(NULL) {}// default ctor
<- remove this line from structure
We could no longer create nodes this way:
node* front = new node;// ERROR - no no-arg ctor
We HAVE TO creat nodes like this:
node* front = new node(3, "a line", NULL);//using the only ctor available
The compiler also automatically supplies a copy ctor and an overload for =.
The default versions perform a straight across member by member copy of values.
The list class actually has only ONE data member, so the default copy ctor for the list class would be quite simple:
1 2 3 4
|
list::list(const list& rList )
{
front = rList.front;
}
|
Or, equivalently:
list::list( const list& rList ): front(rList.front) {}
And for = it would be:
1 2 3 4 5
|
list& list::operator=( const list& rList )
{
front = rList.front;
return *this;// return a reference to the object calling this function
}
|
These default versions do what we would WANT done in most cases.
In our case though this is a disaster.
This assignment:
front = rList.front;
causes both lists to point to the same data.
When we create a copy of a list we need to create a new copy of all of the data in rList
for our front pointer to point to.
Our copy ctor needs to allocate nodes of its own and copy the data from rLists nodes.
The crash occurred because both object.front and object2.front point to the same memory space.
When object2 is destroyed at the end of program execution, it's OK because its front is pointing to valid data.
When object is destroyed, the memory pointed to by its front has already been deleted.
Calling delete on the invalid front* causes the crash.
The crashes are occurring when the destructor for the 2nd list is called.
You may have noticed from the destructors output in our program that objects are destroyed in the reverse order in which they were constructed.
ie:
1 2 3 4 5
|
list object;
list object2( object );
//...
~object2();// object2 destroyed first leaving front =garbage
~object();// object destroyed. Crash occurs.
|
I'll pick apart the new copy ctor and operator= in the next post.
EDIT: I forgot to address this:
one simple thing i cant see too, in the destructor code...it says while (front) |
Sorry, I changed notations on you. Note that
while(front)
is equivalent to:
while(front != NULL)
Similarly,
if( !front )
means the same as:
if(front == NULL)
EDIT2: I just came across these links (posted by cire) in another thread where the same issue is involved.
The 3 member functions we have been considering lately in this thread are the:
1) destructor
2) copy ctor
3) Assignment operator (=) overload.
These are the 3 functions in the "Rule of Three" covered here:
http://en.wikipedia.org/wiki/Rule_of_three_%28C%2B%2B_programming%29
http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three