Invoking Destructor

Here is my code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
class MyString {
	private:
		char * name ;
		
	public : 
		MyString(){
			//do nothing;
		}
		
		MyString(char * n){
			name = new char[strlen(n)+1];
			strcpy(name,n);
		}
		
		char * getName() const{
			return name ;
		}
		
		MyString operator + (MyString obj){
			MyString tempString ;
			tempString.name = new char[strlen(obj.getName()) + strlen(name) + 1];
			strcpy(tempString.name,name); //copy the first string
			strcat(tempString.name,obj.getName()); //concatenate with the second string
			return tempString ;
		}
		
		bool operator <= (MyString obj){
			if(strlen(name) <= strlen(obj.getName())){
				return true ;
			}else {
				return false ;
			}
		}
		
		friend ostream & operator << (ostream &out ,const MyString &obj);
		
		~MyString(){
			cout << "Deallocating memory " << name ;
			delete[] name;
			name = 0;
		}

};


int main(){
	MyString str1("Raman");
	MyString str2("Ghai");
	MyString str3 = str1 + str2 ;
	cout << str3 << "\n"; //does not give any error
	
	if(str1 <= str2 ){
		cout <<"String 1 contains less than or equal characters than String 1" << endl;
	}else {
		cout << "String 1 contains more characters than String 2" << endl;
	}
	return 0 ;
}

I am not able to understand the invokation sequence of destructor in the output

Output:
1
2
3
4
5
6
7
8
9
10
11

Deallocating memory Ghai
RamanGhai

Deallocating memory @/
String 1 contains more characters than String 2
Deallocating memory RamanGhai

Deallocating memory è3/

Deallocating memory Raman

Can anyone please explain ? thanks
You never declared a copy constructor, so when you called operator+() and operator<=() you called the implicit copy constructor generated by the system.

The arguments are passed by value, so the copy constructor is called, and the destructor is called when leaving the function scope. The generated copy constructor copies the pointer to the new object, and the destructor deletes it. By the time you try to delete the originals, the dynamically allocated memory has already been deleted.

Change the arguments to the operators to references. Also, define a copy constructor.
Let consider the code in main step by step. Let start from the following statement

MyString str3 = str1 + str2 ;

It could be rewriten as

MyString str3 = str1.operator + ( str2 ) ;

Let look the definition of the operator +

1
2
3
4
5
6
7
		MyString operator + (MyString obj){
			MyString tempString ;
			tempString.name = new char[strlen(obj.getName()) + strlen(name) + 1];
			strcpy(tempString.name,name); //copy the first string
			strcat(tempString.name,obj.getName()); //concatenate with the second string
			return tempString ;
		}


It has a parameter of type MyString that accepts an argument by value. So a copy constructor has to be called to create local variable (parameter) obj from argument str2. Because you did not define the copy constructor then implicitly defined by the compiler copy constructor will be called. All what it does is assigning str.name to obj.name.

So there are two objects, str and obj, members of which with name 'name' point to the same string.

After exiting this operator object obj will be destroyed. It means that memory pointed to by both name(s) will be freed. The destructor for object obj issues the message

Deallocating memory Ghai


Now the state of object str2 is undefined because its member name points to unallocated memory.

Inside the operator there is another local object with name tempString. It also shall be deleted but due to the compiler optimization it simply becomes str3. That is the compiler does not call the copy constructor and corresponding destructor.

This output

RamanGhai


corresponds to the statement

cout << str3 << "\n"; //does not give any error

Then the following statement is executed

1
2
	if(str1 <= str2 ){
		cout <<"String 1 contains less than or equal characters than String 1" << endl;



that is operator

1
2
3
4
5
6
7
		bool operator <= (MyString obj){
			if(strlen(name) <= strlen(obj.getName())){
				return true ;
			}else {
				return false ;
			}
		}


is called. It again has a parameter that accpets an argument by value. This means that a local object that is a copy of str2 will be created and after exiting the operator will be deleted.

Here the corresponding destructor message for this local object

Deallocating memory @/


Now you have three objects str3, str2 and str1. str2 has undefined state because its member name points to already freed memory. The objects are deleted in the reverse order relative to their creations. So the first will be deleted str3, then str2, and at last str1.

So the last three messages correspond to three call of the destructor

Deallocating memory RamanGhai

Deallocating memory è3/

Deallocating memory Raman

@doug I have changed the objects to references. Now it doesn't create those temporary objects.

@vlad from Moscow... thanks a ton

Still there is a little doubt

After exiting this operator object obj will be destroyed. It means that memory pointed to by both name(s) will be freed. The destructor for object obj issues the message


Then why it didn't crash the program due to this line
 
name = 0 ; // making the pointer null in destructor 

, instead it showed the garbage value . Any ideas about that ?
The destructor is called for a temporary object and it sets its own (that is of temporary object) data member name to zero. The original object that was copied to the temporary object was not changed. In fact when object str2 was deleted after reaching the end of the program there shall be a failure of memory access violation because its data member name points to the already freed memory. I do not know why this does not happen in your system.
That statement is meaningless because it is the last statement of a destructor. All it is doing is setting the value of a pointer to NULL after the memory is freed, just before the object containing the pointer disappears.

That statement does not dereference the pointer, nor does it delete any memory. It also does not modify the values of pointers in other objects that were copied from this one, or that this one is copied from.

If you need a better understanding of pointers and dynamic memory, see the following tutorials:

http://cplusplus.com/doc/tutorial/pointers/
http://cplusplus.com/doc/tutorial/dynamic/
Assigning a pointer to zero(null) is safe. Deleting a Null pointer is safe. That is why your program did not crash. Had you just deleted the pointer in the destructor and not assign null it would have crashed. Next time it attempted to delete it would have crashed.
That statement is meaningless because it is the last statement of a destructor. All it is doing is setting the value of a pointer to NULL after the memory is freed, just before the object containing the pointer disappears.

@doug You are probably right about that. Since I am doing it just before the actual object get's destroyed.It doesn't make any difference here.

In fact when object str2 was deleted after reaching the end of the program there shall be a failure of memory access violation because its data member name points to the already freed memory.

@vlad from moscow I changed the objects to references in the function . Now that problem should not come.

Thanks a lot everyone.
Here's the final output after making changes :
1
2
3
4
5
RamanGhai
String 1 contains more characters than String 2
Deallocating memory RamanGhai
Deallocating memory Ghai
Deallocating memory Raman

Topic archived. No new replies allowed.