Overloading Operators

Started by
8 comments, last by Xtreme 21 years, 1 month ago
hi all, I am trying out this sample code from a book, except that I''m stumped at the output. Can anyone give me any pointers are to why I''m getting 2 destructors called in a row rather than 1? Here is the source:
  

#include <iostream>
using namespace std;

class Counter
{
private:
	unsigned int count;
public:
	Counter() : count(0)
	{ 
		cout << "Constructor called " << endl; 
	}

	~Counter()
	{ 
		cout << "Destructor called " << endl; 
	}

	unsigned int get_count()
	{
		return count;
	}

	Counter operator ++ ()
	{
		++count;
		Counter temp;
		temp.count = count;
		return temp;
	}
};

int main()
{
	Counter c1, c2;

	cout << "\nc1=" << c1.get_count();
	cout << "\nc2=" << c2.get_count();

	++c1;
	c2 = ++c1;

	cout << "\nc1=" << c1.get_count();
	cout << "\nc2=" << c2.get_count() << endl;
	return 0;
}

  
And here is the output:
  

Constructor called
Constructor called

c1=0
c2=0Constructor called //constructor of Counter temp

Destructor called      //destructor of Counter temp

Destructor called      //what destructor does this belong to?

Constructor called     //constructor of Counter temp


Destructor called      //destructor of Counter temp

Destructor called      //same question here?


c1=2
c2=2

  
I''ve debugged it in Visual Studio and the 2 Destructor output occurs at the same time. Any ideas?
Yes! There are kangaroos in Australia but I haven't seen them...yet
Advertisement
my guess would be that it is using the Counter(const Counter&) constructor which you have not defined (therefore the standard is used by the compiler) and your program does therefore not write "contructor called" when this happens. It does however call the one and only destructor that prints "destruc..." etc.
you could try to add Counter(const Counter&) and see if it seems to be a bit more logical it might be it, but i'm not sure


[edited by - Jolle on March 5, 2003 7:12:19 AM]
The line:
return temp;
is where the second destructor is being called. When you return a locally declared object, a new object is created using a ''copy constructor'' since the locally declared object will disappear (destroyed) when the function returns. This new object is then destroyed after the assignment has been completed.

Add the following member function:
Counter (const Counter &source) : count (source.count){	cout << "Copy constructor called " << endl;} 

and all should be revealed.

Your ++ operator should really be:
const Counter &operator ++ (){	++count;	return *this;} 

and that will get rid of all the temporary objects being constructed / destroyed (which can save huge amounts of time).

I suggest reading the "Effective C++" book by Meyers. It discusses this and other issues in some depth.

Skizz
Jolle,
looks like your right! Except for the output of c2 at the end....


  Constructor calledConstructor calledc1=0c2=0Constructor calledConst Constructor calledDestructor calledDestructor calledConstructor calledConst Constructor calledDestructor calledDestructor calledc1=2c2=1243040Destructor calledDestructor calledPress any key to continue  


And here is the modified source:

  #include <iostream>using namespace std;class Counter{private:	unsigned int count;public:	Counter() : count(0)	{ 		cout << "Constructor called " << endl; 	}	Counter(const Counter&) 	{		cout << "Const Constructor called " << endl; 	}	~Counter()	{ 		cout << "Destructor called " << endl; 	}	unsigned int get_count()	{		return count;	}	Counter operator ++ ()	{		++count;		Counter temp;		temp.count = count;		return temp;	}};int main(){	Counter c1, c2;	cout << "\nc1=" << c1.get_count();	cout << "\nc2=" << c2.get_count();	++c1;	c2 = ++c1;	cout << "\nc1=" << c1.get_count();	cout << "\nc2=" << c2.get_count() << endl;	return 0;}  
Yes! There are kangaroos in Australia but I haven't seen them...yet
quote:Original post by Jolle
my guess would be that it is using the Counter(const Counter&) constructor which you have not defined (therefore the standard is used by the compiler) and your program does therefore not write "contructor called" when this happens.

Yes. Assignments for user-defined types are usually implemented as invokations of the copy constructor when operator= is not supplied. If the copy constructor has also not been supplied, the compiler will provide one (which usually performs a bitwise copy).
Skizz,

Thanks for that, i''m already taking the code example from a Object Oriented Programming book. The code was exactly how it was written (except for the Constructor and destructor called part)

My next question is why is the output of c2 garbage?
Yes! There are kangaroos in Australia but I haven't seen them...yet
change it to

Counter(const Counter& rhs){  count = rhs.count;  cout << "Const Constructor called " << endl;}


and it will work... i hope =)

[edited by - Jolle on March 5, 2003 7:27:30 AM]
But it should be Copy contructor, like Skizz said
Jolle,

It worked!! Thanks for that.
Here is the output:


  Constructor calledConstructor calledc1=0c2=0Constructor calledConst Constructor calledDestructor calledDestructor calledConstructor calledConst Constructor calledDestructor calledDestructor calledc1=2c2=2Destructor calledDestructor calledPress any key to continue  
Yes! There are kangaroos in Australia but I haven't seen them...yet
Using my altered operator++ I get this:
Constructor calledConstructor calledc1=0c2=0c1=2c2=2Destructor calledDestructor called 

It''s always good to know what''s going on ''under the hood'' so to speak. When speed is critical, eleminating these ''hidden'' objects can make huge differences.

Also, this test application should be highlighting a possible gotcha. For example, the following looks OK, but in fact, it crashes (and I know std::string will fix this one, it''s just an example of dynamic memory allocation and overloading operators):

  #include <iostream>using namespace std;class CTest{public:	CTest (void) :		m_string (0)	{		cout << "Default constructor called " << endl;	}	CTest (const char *const string) :		m_string (strdup (string))	{		cout << "Constructor called " << endl;	}	CTest (const CTest &rhs) :		m_string (strdup (rhs.m_string))	{		cout << "Copy constructor called " << endl;	}		~CTest ()	{		delete m_string;		m_string = 0;		cout << "Destructor called " << endl;	}	CTest operator ++ (void)	{		return *this;	}	const char *const get_string () const	{		return m_string != 0 ? m_string : "NULL";	}private:	char		*m_string;};void main (void){	CTest		c1 ("C1"),		c2 ("C2");		cout << "c1=" << c1.get_string () << endl;	cout << "c2=" << c2.get_string () << endl;		c1 = ++c2;	cout << "c1=" << c1.get_string () << endl;	cout << "c2=" << c2.get_string () << endl;}   


Skizz

This topic is closed to new replies.

Advertisement