KnowledgeBase Archive

An Archive of Early Microsoft KnowledgeBase Articles

View on GitHub

Q129617: FIX: Destructor Called on Non Constructed Temporary

Article: Q129617
Product(s): Microsoft C Compiler
Version(s): 1.0,1.5,1.51,1.52,2.0,2.1
Operating System(s): 
Keyword(s): kbbuglist kbfixlist
Last Modified: 23-JUL-2001

-------------------------------------------------------------------------------
The information in this article applies to:

- Microsoft C/C++ Compiler (CL.EXE), included with:
   - Microsoft Visual C++, versions 1.5, 1.51, 1.52 
   - *EDITOR Please do not choose this product*Microsoft Visual C++ 32-bit Edition* use 241, 265, 225, versions 1.0, 2.0, 2.1 
-------------------------------------------------------------------------------

SYMPTOMS
========

The destructor of a class is called on a temporary that was never constructed if
all the following conditions exist:

- Two classes A and B are created.

- A global function takes an argument of class B by value.

- A conversion operator is used to convert from class A to class B.

- The global function is called with an item of class A.

The destructor being called for an object that was never constructed can cause a
general protection (GP) fault or other memory errors at run time.

WORKAROUND
==========

Listed below in order of preference are three workarounds to this problem:

- Define a conversion constructor in class B instead of a conversion operator
  in class A.

-or-

- Define the function to take an argument of "const B &" instead of taking
  class B by value.

-or-

- Explicitly instantiate a B object and call the global function with the
  instance of the B object.

The first workaround produces much cleaner code than the other two workarounds.
See the sample code listed below for further details.

STATUS
======

Microsoft has confirmed this to be a bug in the Microsoft products listed at the
beginning of this article. This problem was fixed in Microsoft Visual C++,
32-bit Edition, version 4.0.

MORE INFORMATION
================

The sample code below can be used to reproduce this problem. If the program is
complied with no options, the following output is displayed when the program is
run:

  -- A ctor called
  -- Class A -> Class B conversion called
  -- B ctor called, Created B: 1245064
  -- B copy ctor, Created B: 1245096
  -- B dtor called, Destroyed B: 1245064
  -- Calling function test(B) on B: 1245076
  -- B dtor called, Destroyed B: 1245076
  This B was never constructed!
  -- B dtor called, Destroyed B: 1245096
  -- A dtor called

Sample Code to Reproduce Problem
--------------------------------

  /* Compile options needed, choose one of the following:
            none           - To demonstrate the problem.
            /DWORKAROUND1  - For workaround 1.
            /DWORKAROUND2  - For workaround 2.
            /DWORKAROUND3  - For workaround 3.
  */ 

  #include <iostream.h>

  class A;

  class B
  {
     B *pBthis;
  public:
     B() {
        pBthis = this;
        cout << "-- B ctor called, Created B: " << (long)this << endl;
     }
  #ifdef WORKAROUND1
     B(const A&) {
        pBthis = this;
        cout << "-- B(A) ctor called, Created B: " << (long)this << endl;
     }
  #endif
     B( const B& b ) {
        pBthis = this;
        cout << "-- B copy ctor, Created B: " << (long)this << endl;
     }
     ~B() {
        cout << "-- B dtor called, Destroyed B: " << (long)this << endl;
       if (pBthis != this)
           cout << "    This B was never constructed!" << endl;
     }
  };

  class A
  {
  public:

     A() { cout << "-- A ctor called" << endl; }
     ~A() { cout << "-- A dtor called" << endl; }

  #ifndef WORKAROUND1
     operator B() {
        cout << "-- Class A -> Class B conversion called" << endl;
        B b1;
        return b1;
     }
  #endif

  };

  #ifdef WORKAROUND2
  void test(const B &b)
  #else
  void test(B b)
  #endif
  {
     cout << "-- Calling function test(B) on B: " << (long)(&b) << endl;
  }

  int main()
  {
     A a;
  #ifdef WORKAROUND3
     B b(a);
     test(b);
  #else
     test(a);
  #endif
     return 0;
  }

Additional query words: 1.00 1.50 1.51 1.52 2.00 2.10 8.0 8.00 8.0c 8.00c 9.0 9.00 GPF

======================================================================
Keywords          :  kbbuglist kbfixlist
Technology        : kbVCsearch kbAudDeveloper kbCVCComp
Version           : :1.0,1.5,1.51,1.52,2.0,2.1
Issue type        : kbbug
Solution Type     : kbfix

=============================================================================

THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Copyright Microsoft Corporation 1986-2002.