Archived

This topic is now archived and is closed to further replies.

Xtreme

Overloading Operators

Recommended Posts

Xtreme    122
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?

Share this post


Link to post
Share on other sites
Jolle    178
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]

Share this post


Link to post
Share on other sites
Skizz    794
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

Share this post


Link to post
Share on other sites
Xtreme    122
Jolle,
looks like your right! Except for the output of c2 at the end....


  

Constructor called
Constructor called

c1=0
c2=0Constructor called
Const Constructor called
Destructor called
Destructor called
Constructor called
Const Constructor called
Destructor called
Destructor called

c1=2
c2=1243040
Destructor called
Destructor called
Press 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;
}

Share this post


Link to post
Share on other sites
Oluseyi    2107
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).

Share this post


Link to post
Share on other sites
Xtreme    122
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?

Share this post


Link to post
Share on other sites
Jolle    178
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]

Share this post


Link to post
Share on other sites
Xtreme    122
Jolle,

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


  

Constructor called
Constructor called

c1=0
c2=0Constructor called
Const Constructor called
Destructor called
Destructor called
Constructor called
Const Constructor called
Destructor called
Destructor called

c1=2
c2=2
Destructor called
Destructor called
Press any key to continue

Share this post


Link to post
Share on other sites
Skizz    794
Using my altered operator++ I get this:

Constructor called
Constructor called

c1=0
c2=0
c1=2
c2=2
Destructor called
Destructor 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

Share this post


Link to post
Share on other sites