murison@cfa.HARVARD.EDU (Marc A. Murison, RG) (03/10/91)
Dear NetFolks,
There seems to be a bug in the new Borland C++ 2.0 that was not
in Turbo C++ 1.0. When a temporary object is created, it is not
properly deleted when it goes out of scope. For example, suppose
we create a String object, then assign a character string to it:
/* ... */
{
String A; //default ctor called here
A = "anteater"; //conversion ctor creates a temp. object here
}
At this point (A goes out of scope), I *thought* there should've
been two constructor calls and two corresponding destructor calls.
In a test program (listed below for those who want to try it), bcc makes
two constructor calls and only one destructor call, whereas tcc
behaves as (I) expected. In examining the output (shown below), one
sees that the temporary object is not being deleted in the case of bcc.
I haven't tried this with the IDE compilers.
Is this a bug? Can someone please enlighten me?
Thanks,
Marc A. Murison
murison@cfacx2.harvard.edu
=======================================================================
Here is the output from the test program listed below:
output from BCC 2.0:
--------------------
startmem = 60544
In default constructor:
Address of this object is 0X104FFFEC
In conversion constructor: text = "anteater"
Address of this object is 0X104FFFE8
In operator =: duplicating "anteater" to this->text
Address of this object is 0X104FFFEC
Address of copied object is 0X104FFFE8
After assignment: mem = 60512
Objects temp and A use 32 bytes.
In destructor: text = "anteater"
Address of this object is 0X104FFFEC
endmem = 60528
Memory difference = 16 bytes
output from TCC 1.0:
--------------------
startmem = 60320
In default constructor:
Address of this object is 0X1252FFEC
In conversion constructor: text = "anteater"
Address of this object is 0X1252FFE8
In operator =: duplicating "anteater" to this->text
Address of this object is 0X1252FFEC
Address of copied object is 0X1252FFE8
After assignment: mem = 60304
Objects temp and A use 16 bytes.
In destructor: text = "anteater"
Address of this object is 0X1252FFE8
In destructor: text = "anteater"
Address of this object is 0X1252FFEC
endmem = 60320
Memory difference = 0 bytes
----- snip ---- snip ----------- STRTEST.CPP ---------- snip ----- snip -----
/*
*
* test for bug in Borland BC++ 2.0
*
* Marc A. Murison
* murison@cfacx2.harvard.edu
*
*/
#include "str.hpp"
#include <alloc.h>
void main( void )
{
unsigned startmem, endmem;
startmem = coreleft(); //BC++ function to get available core
cout << "\nstartmem = " << coreleft() << endl;
//uppercase on hex output
cout.flags(ios::uppercase);
//dtor should be called twice as A goes out of scope in this block:
{
String A; //default ctor called here
A = "anteater"; //conversion ctor creates a temp. object here
cout << "\nAfter assignment: mem = " << coreleft();
cout << "\nObjects temp and A use " << (startmem - coreleft())
<< " bytes." << endl;
}
endmem = coreleft();
cout << "\nendmem = " << coreleft();
cout << "\nMemory difference = " << (startmem - endmem) << " bytes"
<< endl;
}
----- snip ---- snip ----------- STR.HPP ---------- snip ----- snip -----
/*
*
* class String header file for use with STR.CPP and STRTEST.CPP
*
*/
#include <string.h>
#include <iostream.h>
#pragma hdrstop
class String {
protected:
char *text;
int length;
public:
String( void );
String( const char *string );
~String( void );
String& operator = ( const String &string );
};
----- snip ---- snip ----------- STR.CPP ---------- snip ----- snip -----
/*
*
* class String implementation for use with STRTEST.CPP
*
*/
#include "str.hpp"
//
// default constructor
//
String::String( void )
{
length = 0;
text = NULL;
cout << "\n In default constructor:";
cout << "\n Address of this object is " << (&(*this)) << endl;
}
//
// conversion constructor
//
String::String( const char *string )
{
if( string == NULL ) {
length = 0;
text = NULL;
} else {
length = strlen(string);
text = new char [length + 1];
if( text == NULL )
cerr << "\a\nMemory allocation error in conversion ctor\n";
else
strcpy( text, string );
}
if( text != NULL )
cout << "\n In conversion constructor: text = \"" << text << "\"";
else
cout << "\n In conversion constructor: text = NULL";
cout << "\n Address of this object is " << (&(*this)) << endl;
}
//
// destructor
//
String::~String()
{
if( text != NULL )
cout << "\n In destructor: text = \"" << text << "\"";
else
cout << "\n In destructor: text = NULL";
cout << "\n Address of this object is " << (&(*this)) << endl;
if( text != NULL ) delete text;
}
//
// assignment operator
//
String& String::operator = (const String &string )
{
cout << "\n In operator =: duplicating \""
<< string.text << "\" to this->text";
cout << "\n Address of this object is " << (&(*this));
cout << "\n Address of copied object is " << (&string) << endl;
length = string.length;
if( text != NULL ) delete text;
text = new char [length + 1];
if( text == NULL )
cerr << "\a\nMemory allocation error in operator =\n";
else
strcpy( text, string.text );
return *this;
}
----- snip ---- snip ----------- END ---------- snip ----- snip -----