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 -----