In this lecture...
Using Destructors. Queues. Copy Constructor. Assignment Operator. 
chapter 2.2.4 in the textbook.
A destructor is a special member of a class. A class destructor is called automatically. The destructor name is the tilde (~) character followed by the class name.
A destructor has NO parameters and NO return value (even void cannot be specified). There is only one destructor in a class.
class Demo {
public:
      Demo( int x ) : data(x) {cout<<"object "<x<" constructed";}  
     ~Demo()    {cout<<"object "<<data<<" destructed"<<endl;}    
private:
	int data;
};
Constructors and destructors are called each time when you allocate and/or deallocate memory by using new and delete:
int main( void )
{
	Demo *tmp = new Demo(10);
	cout << endl;
	delete tmp; //comment out this line and see the difference
	
	return 0;
}
Exercise. How would you call the destructor directly (without calling delete)?
Destructors for automatic objects  are called each time when the object enters or leaves the scope. Destructors for static objects are called when main() terminates.
Here is the program which demonstrates the order of calling constructor and destructor:
int main( void )
{
	Demo one( 1 );
	cout << "   (local automatic in main)" << endl;
	static Demo two( 2 );
	cout << "   (local static in main)" << endl;
	Demo three( 3 );
	cout << "   (local automatic in main)" << endl;
	return 0;
}
Let us add the function create() which creates a few more objects. Here is a complete code.
Queues have many applications in computer systems: printer queue, system queue, information packets in the network, file access
As with stacks, we can implement a queue using either linked lists or arrays. In both cases we need to keep track the beginning and the end of a queue, since it grows and shrinks as elements are inserted and deleted.
Node. We want the queue to have member functions Dequeue, Enqueue, Print, IsEmpty, RemoveAll
class Queue
{
 public:
    // default constructor
    Queue () : HeadOfQueue(NULL),BackOfQueue(NULL) {}
    // copy constructor
    
    // destructor
    
    // accessor
    bool IsEmpty() const;
    void Print() const;  // print a queue
    
    // member functions
    void Enqueue(const int &); // add item to the back
    bool Dequeue(int &);  // return and remove least recent item       
    void RemoveAll();       
    
 private:
    Node* HeadOfQueue;
    Node* BackOfQueue;
};
Declaration
Stack(const Stack &);
S2 which is initialized to a copy of S. The copy constructor performs a memberwise copy - each member of one object is copied individually to the same member in another class. 
Stack S2 = S;
 S2 = S )
Implementation (for stack)
Stack::Stack(const Stack &rhs)
{
	HeadOfStack = NULL; // initialize lhs
	*this = rhs;        // point lhs to rhs object
}
HeadOfStack and this point to the left hand side class.
Exercise. Implement a copy constructor for the queue.
You should understand the difference between initialization and assignment. Initialization uses the copy constructor to create a new object, the assignment operator S2 = S deals with an existent object S2 and modifies it so that it is an identical copy of S.
The problems occurs when when the member of a class is a pointer. The copy constructor will copy the value of the pointer, which lead to having two pointers to the same object. This is so-called shallow copy. To avoid this problem you have to implement your own assignment operator, a deep copy.
Typically, when a class contains pointers as data members we must implement the destructor, copy constructor and operator=.
Declaration
const Queue & operator=(const Queue &);
When you do assignment  S2 = S  you should make sure that 
this != &rhs
const Queue& Queue::operator=(const Queue &rhs)
{
   if (this != &rhs)  
   {
	  RemoveAll();   
	  if (rhs.IsEmpty()) return *this;
//we copy the first node
//tmp points to rhs (right hand side)
//new_tmp points to lhs (left hand side)
	  HeadOfQueue = new Node(rhs.HeadOfQueue->data);
	  Node* tmp = rhs.HeadOfQueue->next;
	  Node* new_tmp = HeadOfQueue;
//in a loop we cope all other nodes
	  while (tmp)  	
	  {
	     new_tmp = new_tmp->next = new Node(tmp->data);
	     tmp = tmp->next;
	  }
   	  BackOfQueue = new_tmp;
   }
   return *this;  //why do we return a pointer this?
HeadOfStack, new_tmp and this point to a new stack.What should the assignment operator return? Think about the following infinite loop
while(x = 7);
Last updated February 01, 2001.
|  | Please send corrections to Victor
S. Adamchik, Computer Science Department, Carnegie Mellon University, Pittsburgh, PA. |