468,760 Members | 1,720 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,760 developers. It's quick & easy.

why does this call the destructor?

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::ostream;

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
May 4 '07 #1
7 1867
michael wrote:
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)
^^^^^ ^
^^^^^ ^
May 4 '07 #2
"anon" <an**@no.nowrote in message
news:f1**********@el-srv04-CHE.srvnet.eastlink.de...
michael wrote:
>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)
^^^^^ ^
^^^^^ ^
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
May 4 '07 #3
On May 4, 11:14 am, "michael" <s...@begone.netwrote:
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::ostream;

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?

May 4 '07 #4
On 4 Maj, 08:43, "michael" <s...@begone.netwrote:
"anon" <a...@no.nowrote in message

news:f1**********@el-srv04-CHE.srvnet.eastlink.de...
michael wrote:
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 asa
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.
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.

--
Erik Wikström

May 4 '07 #5
On Fri, 04 May 2007 08:14:57 +0200, michael <sp**@begone.netwrote:
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::ostream;

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

--
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
May 4 '07 #6
Erik Wikström wrote:
On 4 Maj, 08:43, "michael" <s...@begone.netwrote:
>"anon" <a...@no.nowrote in message

news:f1**********@el-srv04-CHE.srvnet.eastlink.de...
>>michael wrote:
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)
^^^^^ ^
^^^^^ ^
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.
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.
May 4 '07 #7

"michael" <sp**@begone.netwrote in message
news:46***********************@per-qv1-newsreader-01.iinet.net.au...
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::ostream;

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.

May 5 '07 #8

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

3 posts views Thread by Martin Koller | last post: by
23 posts views Thread by Fabian Müller | last post: by
15 posts views Thread by Roy Smith | last post: by
9 posts views Thread by Daniel Kay | last post: by
9 posts views Thread by rohits123 | last post: by
19 posts views Thread by Angus | last post: by
6 posts views Thread by Pallav singh | last post: by
reply views Thread by zhoujie | last post: by
reply views Thread by Marin | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.