Microsoft KB Archive/246550: Difference between revisions

From BetaArchive Wiki
m (Text replacement - "<" to "<")
m (Text replacement - """ to """)
 
(2 intermediate revisions by the same user not shown)
Line 57: Line 57:
<div class="indent">
<div class="indent">


&quot;The zero-initialization [construction] of all local objects with static storage duration is performed before any other initialization takes place. ... such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization [upon completion of its constructor] . If the initializations exits by throwing an exception, the initialization is not complete, so it will be tried again [constructor called again] the next time control enters the declaration. ...&quot;
"The zero-initialization [construction] of all local objects with static storage duration is performed before any other initialization takes place. ... such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization [upon completion of its constructor] . If the initializations exits by throwing an exception, the initialization is not complete, so it will be tried again [constructor called again] the next time control enters the declaration. ..."




Line 67: Line 67:
== RESOLUTION ==
== RESOLUTION ==


There are several potential ways to workaround the behavior, including removing the static keyword from the variable declaration, having the class constructor catch and handle the exception, not using exceptions, using a separate initialization function to emulate proper behavior, and so forth. The actual approach you choose will be greatly dependent upon your individual project. See the &quot;More Information&quot; section for an example of the separate initialization approach.
There are several potential ways to workaround the behavior, including removing the static keyword from the variable declaration, having the class constructor catch and handle the exception, not using exceptions, using a separate initialization function to emulate proper behavior, and so forth. The actual approach you choose will be greatly dependent upon your individual project. See the "More Information" section for an example of the separate initialization approach.


</div>
</div>
Line 83: Line 83:
=== Steps to Reproduce Behavior ===
=== Steps to Reproduce Behavior ===


The following code sample illustrates the problem. Define the &quot;workaround to see the separate initialization function approach.<br />
The following code sample illustrates the problem. Define the "workaround to see the separate initialization function approach.<br />


<pre class="codesample">// compile options:  /GX  
<pre class="codesample">// compile options:  /GX  
#include <iostream&gt;
#include <iostream>


class MyClass
class MyClass
Line 92: Line 92:
public:
public:
     MyClass() { throw(int()); }
     MyClass() { throw(int()); }
     MyClass(const MyClass&amp; cClass) {}
     MyClass(const MyClass& cClass) {}
     MyClass&amp; operator=(const MyClass &amp;co) {return *this;}
     MyClass& operator=(const MyClass &co) {return *this;}
     virtual ~MyClass() {}
     virtual ~MyClass() {}
};
};
Line 142: Line 142:
           {
           {
               MyFunction();
               MyFunction();
               cout << &quot;No Exceptions Thrown / All Exceptions Handled\n&quot;;
               cout << "No Exceptions Thrown / All Exceptions Handled\n";
           }
           }
           catch(int)
           catch(int)
           {
           {
               cout << &quot;An int Exception Was Thrown and Not Handled\n&quot;;
               cout << "An int Exception Was Thrown and Not Handled\n";
           }
           }
     }
     }

Latest revision as of 12:50, 21 July 2020

Article ID: 246550

Article Last Modified on 7/5/2005



APPLIES TO

  • Microsoft Visual C++ 6.0 Enterprise Edition
  • Microsoft Visual C++ 6.0 Professional Edition
  • Microsoft Visual C++ 6.0 Standard Edition



This article was previously published under Q246550

SYMPTOMS

After the constructor for a local static variable throws an exception, the constructor is not called the next time there is a call to the function in which the variable is declared.

CAUSE

The Visual C++ Compiler has not correctly implemented the behavior dictated by the ANSI C++ specification. The ANSI specification, section 6.7 states in part:

"The zero-initialization [construction] of all local objects with static storage duration is performed before any other initialization takes place. ... such an object is initialized the first time control passes through its declaration; such an object is considered initialized upon the completion of its initialization [upon completion of its constructor] . If the initializations exits by throwing an exception, the initialization is not complete, so it will be tried again [constructor called again] the next time control enters the declaration. ..."


RESOLUTION

There are several potential ways to workaround the behavior, including removing the static keyword from the variable declaration, having the class constructor catch and handle the exception, not using exceptions, using a separate initialization function to emulate proper behavior, and so forth. The actual approach you choose will be greatly dependent upon your individual project. See the "More Information" section for an example of the separate initialization approach.

STATUS

Microsoft has confirmed that this is a bug in the Microsoft products that are listed at the beginning of this article.

MORE INFORMATION

Steps to Reproduce Behavior

The following code sample illustrates the problem. Define the "workaround to see the separate initialization function approach.

// compile options:  /GX 
#include <iostream>

class MyClass
{
public:
     MyClass() { throw(int()); }
     MyClass(const MyClass& cClass) {}
     MyClass& operator=(const MyClass &co) {return *this;}
     virtual ~MyClass() {}
};

#ifdef WORKAROUND
class MyClassWrapper : public MyClass
{
public:
// Here, m_InitFlag is set to false in the initialize list
// (Before MyClass() is called), and then set to true
// in the body of the constructor (after MyClass() is called)
     MyClassWrapper() : m_InitFlag(false) {m_InitFlag = true;}
     void init()
     {
          if(!m_InitFlag)
          {
               MyClass tmp;
               *((MyClass *)this) = tmp;
               m_InitFlag = true;
          }
     }
private:
    bool m_InitFlag;
};
#endif //WORKAROUND

#ifdef WORKAROUND
typedef MyClassWrapper StaticClass;
#else
typedef MyClass StaticClass;
#endif //WORKAROUND

void MyFunction()
{ 
    static StaticClass MyObject;
#ifdef WORKAROUND
    MyObject.init();
#endif //WORKAROUND
}

int main()
{
     using std::cout;

     for(int i = 0; i < 2; i++)
     {
          try
          {
               MyFunction();
               cout << "No Exceptions Thrown / All Exceptions Handled\n";
          }
          catch(int)
          {
               cout << "An int Exception Was Thrown and Not Handled\n";
          }
     }

     return 0;
}
// end program
                

Output:

An int Exception Was Thrown and Not Handled
No Exceptions Thrown / All Exceptions Handled
                

Output if WORKAROUND defined:

An int Exception Was Thrown and Not Handled
An int Exception Was Thrown and Not Handled
                


Additional query words: Exception Constructor ANSI

Keywords: kbbug kbcpponly kbpending KB246550