473,405 Members | 2,349 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,405 software developers and data experts.

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 2116
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 thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

3
by: Martin Koller | last post by:
Hi list, I have a small example which gives me "pure virtual function called". I'm calling a virtual function in the destructor of the base class, where the pointer used is effectively...
23
by: Fabian Müller | last post by:
Hi all, my question is as follows: If have a class X and a class Y derived from X. Constructor of X is X(param1, param2) . Constructor of Y is Y(param1, ..., param4) .
15
by: Roy Smith | last post by:
I understand that "delete xp" deletes a scalar object and "delete xp" deletes an array of objects, but what I don't understand is why you need to tell the compiler which you're doing. When you...
7
by: Divick | last post by:
Hi, can somebody please help me figure out what is wrong with the following program? If I run this program, then the destructor for the first pointer in the array is called because exception...
9
by: Daniel Kay | last post by:
Hello! I have written two template classes which implement the observerpattern in C++. I hope I manage to desribe the problem I have. template<class T> class Observer { /* ... */ }; ...
9
by: rohits123 | last post by:
I have an overload delete operator as below ////////////////////////////////// void operator delete(void* mem,int head_type) { mmHead local_Head = CPRMemory::GetMemoryHead(head_type);...
19
by: Angus | last post by:
I have a socket class CTestClientSocket which I am using to simulate load testing. I create multiple instances of the client like this: for (int i = 0; i < 5; i++) { CTestClientSocket* pTemp...
5
by: Warren Tang | last post by:
Hello, Does C++ allow a constructor to call another constructor of the same class? (I am focusing on the language abilities. I know the C# language allow this.) The following sample can...
6
by: Pallav singh | last post by:
Hi All How Does compiler implement virtual destructor ??? as we all know if base class destructor is virtual..........then while wriiting statemnt like this Base * b = new Derived( );...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.