BUG : Destructor Called Erroneously

ID: Q131148

1.00 1.50 1.51 1.52 WINDOWS kbprg kbbuglist

The information to this article applies to :

SYMPTOMS

The destructor may be called for an object not created. This is not a common problem. It happens under a specific circumstances and the sample code in the "More Information" section demonstrates this behavior.

RESOLUTION

Two workarounds are suggested in the sample code (see NOTE #1 and NOTE #2). These workarounds may change the intended behavior of the code.

STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article. We are researching this problem and will post new information here in the Microsoft Knowledge Base as it becomes available.

MORE INFORMATION

Sample Code to Demonstrate Problem

/* No special compile options needed. */ 

#include <iostream.h>

//AString

int stringNumber = 0;

void outputDebug(char *className, char *func, int number)
{

   cout << "in " << className  << "::" << className;
   cout << "() #" << number  << " " << func << endl;

}

class AString{

public:

     AString();
     AString(const AString &orig);
     virtual ~AString();

     AString &operator=(const AString &orig);

protected:
     int number;
private: };

AString::AString() {

   number = ++stringNumber;
   outputDebug("AString", "copy1 constructor", number);
}

AString::AString(const AString &orig) {

   number = ++stringNumber;
   outputDebug("AString", "copy2 constructor", number);
}

AString::~AString() {

   outputDebug("AString", "Destructor", number);
}

AString &AString::operator=(const AString &orig) {

   outputDebug("AString", "operator=", number);
   return *this;
}

//ACompressor

class ACompressor { public:
       ACompressor(AString& base);
       ~ACompressor();
};

inline ACompressor::ACompressor(AString& baseObject){

                    outputDebug("ACompressor", "Constructor", 33);}

inline ACompressor::~ACompressor(){ outputDebug("ACompressor", "Destructor",

                                    33);}

//APath

class APath : private AString{ public:
        APath() : AString(){}
        APath(char *) : AString(){}

        APath &operator =(const APath &path);

        //NOTE #1: if the line below is removed, the extraneous
        //call to AString::~AString() is not generated.
         inline operator AString() const { return *(AString *) this;}

protected: private:
         APath(const APath &path);
 };

APath &APath::operator =(const APath &orig) {
        //NOTE #2:if the line below is removed OR the one in the NOTE #1 is
        //removed, the extraneous AString::~AString() call is not
        //generated.
        ACompressor pc(*this);

        //NOTE #3: The line below generates a call to
        //APath::operator AString().
        AString::operator=(orig);

        //NOTE #4: Extra AString::~AString() destructor call made here
        //Assembly listing shows the extra destructor call.

        return *this;
}

int main()

{
      char *filename = "c:\\someprog.exe";

      APath exePath;
      exePath = filename;

      return 0;
}

Additional reference words: 1.00 1.50 1.51 1.52 8.00 8.00c KBCategory: kbprg kbbuglist KBSubcategory: CPPIss

Keywords          : kb16bitonly kbCompiler kbCPPonly kbVC kbbuglist
Version           : 1.00 1.50 1.51 1.52
Platform          : WINDOWS

Last Reviewed: July 22, 1997