why does this call the destructor?

M

michael

Hi All,

I have written the following to illustrate a problem.
I know I have some magic numbers etc please ignore them.
What I do not follow is why the line marked results in a call to the
destructor for the object.

Can someone please explain it for me?

#include <iostream>
#include <fstream>

using std::eek:stream;

class someClass {
private:
char *str;
public:
someClass();
~someClass();
friend ostream& operator <<(ostream& lhs, someClass rhs);
};

someClass::someClass(){
str = new char[10];
strcpy(str, "something");
}

someClass::~someClass(){
std::cout << "\nIn someClass destructor...\n";
delete str;
}

ostream& operator <<(ostream& lhs, someClass rhs){
lhs << rhs.str; // This results in a call to the destructor for
the someClass object....why?
return lhs;
}

int main(){
someClass soc;
std::cout << soc;
}

Thanks for your help

Regards

Michael
 
A

anon

michael said:
ostream& operator <<(ostream& lhs, someClass rhs){
lhs << rhs.str; // This results in a call to the destructor for
the someClass object....why?
return lhs;
}

It is not that line that calls the destructor, but 2 lines later ( the }
bracket). The destruction of that object happens, because temporary
object rhs of type SomeClass needs to be destroyed. If you used a
reference as a parameter, it wouldn't happen:
ostream& operator <<(ostream& lhs, const someClass& rhs)
^^^^^ ^
^^^^^ ^
 
M

michael

anon said:
It is not that line that calls the destructor, but 2 lines later ( the }
bracket). The destruction of that object happens, because temporary object
rhs of type SomeClass needs to be destroyed. If you used a reference as a
parameter, it wouldn't happen:
ostream& operator <<(ostream& lhs, const someClass& rhs)
^^^^^ ^
^^^^^ ^

Thanks for the reply, and you are of course correct the temporary rhs needs
to be destroyed hence the call, but if it is only the temporary rhs that
gets destroyed, why if I make a second << call like:

int main(){
someClass soc;
std::cout << soc;
std::cout << soc;
}

does the someClass object no longer exist?
Surely the copy should have been destroyed, not the original, especially
since I didn't pass it by reference.

Regards

Michael
 
S

sam_cit

Hi All,

I have written the following to illustrate a problem.
I know I have some magic numbers etc please ignore them.
What I do not follow is why the line marked results in a call to the
destructor for the object.

Can someone please explain it for me?

#include <iostream>
#include <fstream>

using std::eek:stream;

class someClass {
private:
char *str;
public:
someClass();
~someClass();
friend ostream& operator <<(ostream& lhs, someClass rhs);

};

someClass::someClass(){
str = new char[10];
strcpy(str, "something");

}

someClass::~someClass(){
std::cout << "\nIn someClass destructor...\n";
delete str;

}

ostream& operator <<(ostream& lhs, someClass rhs){
lhs << rhs.str; // This results in a call to the destructor for
the someClass object....why?
return lhs;

}

int main(){
someClass soc;
std::cout << soc;

}

Thanks for your help

Regards

Michael

When you pass a variable (object) by value to a function, the value is
stored in the new memory location in the stack. In this case, when
memory is allocated for the object the ctr and dtr should be invoked,
isn't it?
 
?

=?iso-8859-1?q?Erik_Wikstr=F6m?=

Thanks for the reply, and you are of course correct the temporary rhs needs
to be destroyed hence the call, but if it is only the temporary rhs that
gets destroyed, why if I make a second << call like:

int main(){
someClass soc;
std::cout << soc;
std::cout << soc;

}

does the someClass object no longer exist?
Surely the copy should have been destroyed, not the original, especially
since I didn't pass it by reference.

The someObject still exists but you have deleted the string which the
member str points to. Take this as a lesson, when you allocate memory
in the constructor you should also make sure to implement the copy-
constructor and assignment operator (the rule of three I think it's
called) or things like this will bite you.
 
B

Ben Schumeth

Hi All,

I have written the following to illustrate a problem.
I know I have some magic numbers etc please ignore them.
What I do not follow is why the line marked results in a call to the
destructor for the object.

Can someone please explain it for me?

#include <iostream>
#include <fstream>

using std::eek:stream;

class someClass {
private:
char *str;
public:
someClass();
~someClass();
friend ostream& operator <<(ostream& lhs, someClass rhs);
};

someClass::someClass(){
str = new char[10];
strcpy(str, "something");
}

someClass::~someClass(){
std::cout << "\nIn someClass destructor...\n";
delete str;
}

use delete[]
ostream& operator <<(ostream& lhs, someClass rhs){
lhs << rhs.str; // This results in a call to the destructor
for
the someClass object....why?
return lhs;
}

The destructor is not called where you think it is, but when control
reaches the end of the function. This is indeed the destructor of the
copy, not of the original object. Your problem here however is that the
destructor deletes the memory pointed to by str. This is *the same
memory* as in the original object. To create the copy, the compiler had
to create a copy constructor. However this copy constructor only copied
the pointer, not its contents. Conceptually, this is the same as if you
had written:

class someClass()
{
// same as what you wrote, but with this addition:
someClass( const someClass& rhs )
{
str = rhs.str; // only copies the pointer, not the memory it points
to
}
};

Solve this by adding a copy constructor and assignment operator. And of
course you should pass arguments by const reference here - although in
this case that would have meant you wouldn't have found the problem with
your code.

Ben
 
A

anon

Erik said:
The someObject still exists but you have deleted the string which the
member str points to. Take this as a lesson, when you allocate memory
in the constructor you should also make sure to implement the copy-
constructor and assignment operator (the rule of three I think it's
called) or things like this will bite you.

Sorry that I cut the original message so much :(

Yes, the default copy constructor will just copy address of the string
char *str;
from the original to the copy. In the destructor called when the copy is
destoyed, str will be deleted, making both original and copy unusable.
 
J

Jim Langston

michael said:
Hi All,

I have written the following to illustrate a problem.
I know I have some magic numbers etc please ignore them.
What I do not follow is why the line marked results in a call to the
destructor for the object.

Can someone please explain it for me?

#include <iostream>
#include <fstream>

using std::eek:stream;

class someClass {
private:
char *str;
public:
someClass();
~someClass();
friend ostream& operator <<(ostream& lhs, someClass rhs);
};

someClass::someClass(){
str = new char[10];
strcpy(str, "something");
}

someClass::~someClass(){
std::cout << "\nIn someClass destructor...\n";
delete str;
}

ostream& operator <<(ostream& lhs, someClass rhs){
lhs << rhs.str; // This results in a call to the destructor for
the someClass object....why?
return lhs;
}

int main(){
someClass soc;
std::cout << soc;
}

Thanks for your help

(I actually wanted to reply to your later post but anon snipped out too much
of the message).

The class still exists. The problem is you didn't follow the rule of 3. In
a nutshell: A class with any of {destructor, assignment operator, copy
constructor} generally needs all 3

The problem is that your class is being copied by the operator<< function,
and the copy is being deleted when the function ends. But your destructor
deletes your str char*. Which points to your original str* so it is the one
getting deleted, and your orignal becomes corrupt.

This is where the rule of three comes in. Since you need a destructor,
you'll need an assigment operator and copy constructor to go along with it.
In your copy constructor you could allocate memory for the copy of str, then
strcpy the value in.

Myself, when I find that I need a destructor I right away make a copy
constructor and an assignment operator private to the class with no code.
Since they're private, they can't be called. Usually when I find myself
allocating memory in a class I don't WANT the classs to ever be copied (but
that's just me). If I find that, actually, yes, I want to be able to copy
this class, then I will go ahead and correctly code the copy and assignment
operators.

Just add this to your class and try to compile and you'll see the problems:

private:
// No copy or assignment yet so disable by making private.
someClass ( someClass const& /*CopyThis*/ ) { } // Copy constructor.
someClass& operator=( someClass const& /*CopyThis*/ ) { } // Assignment.

now try to compile your code. Everywhere you get an error stating there is
no public copy or assignment operator would of been a bug in your program.
Either change your code so you don't have to make copies (pass references
instead of by value, etc...) or correctly code the copy constructor and
assignment operator so the copies have their own copy of str which they can
delete with inpunity.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top