C++ Exception Handling

Quick quiz: What is the behavior of the following code:

#include <stdio.h>

int main(int argc, char* argv[])
{
    try
    {
        *((char*) 0) = 1;
    }
    catch (...)
    {
        printf("Caught exception.\n");
    }

    return 0;
}

Surprisingly, it depends! As I would expect, on many operating system / compiler combinations (such as gcc version 3.4.4 20050721 (Red Hat 3.4.4-2) as tested by Keith Garner), the dereference of the null pointer leads to a segmentation fault. However, both Microsoft Visual Studio 6.0 and Visual Studio .NET 2003 print the message Caught exception. and exit gracefully. Strange!

This behavior appears to be an unintended consequence of the way C++ exceptions were implemented by Microsoft. Seemingly, Visual C++ implements the C++ exception handling mechanism using Structured Exception Handling (SEH), and the null pointer dereference leads to a Structured Exception, most likely an EXCEPTION_ACCESS_VIOLATION. (For a list of possible SEH codes, see the documentation for the GetExceptionCode() function.) The catch (...) statement ends up catching the Structured Exception, and the code proceeds accordingly.

This means that in Visual C++ 6.0 and Visual C++ .NET 2003, catch (...) does not catch only exceptions thrown using the C++ throw keyword; rather, it may also catch any number of Structured Exceptions, including division by 0, stack overflow, data misalignment, etc. Fortunately, it seems that this behavior may be disabled with the /EHs compiler option in Visual C++ .NET 2005.

However, until the day comes when all Windows code is compiled with Visual C++ .NET 2005 and the /EHs option, I suggest avoiding the catch (...) construct altogether. Personally, I’ve chosen to inherit my custom-defined exceptions from STL’s std::exception and use catch (const std::exception& ex) instead.

Advertisements

Implementing IXmlWriter Part 14: Supporting Writing To A Stream

This is part 14 of my Implementing IXmlWriter post series.

Today I will add support for writing the generated XML to a C++ stream to last time’s IXmlWriter.

Finally the reason why I’ve insisted on calling this series IXmlWriter (instead of StringXmlWriter) should become clear: I’ve been planning on supporting writing the generated XML to more than just a string. Specifically, today I will add the ability to write the XML to a C++ ostream object, a base class in the C++ iostream library which defines a writable stream.

To this end, I decided to write a pure-virtual interface called IXmlWriter which contains all the relevant methods for generating XML (e.g. WriteStartElement(), WriteComment(), etc.), and two concrete classes which implement this interface: StringXmlWriter (which writes to a string as before) and OstreamXmlWriter (which writes to a user-provided ostream instance). I moved the XML-generating logic from StringXmlWriter to OstreamXmlWriter and implemented StringXmlWriter in terms of OstreamXmlWriter and a stringstream instance.

The area where I probably spent the most time was deciding how to pass the ostream instance to OstreamXmlWriter and how OstreamXmlWriter would store it, if necessary. I came up with the following options:

  1. OstreamXmlWriter is passed a copy (or const reference) of the ostream instance in its constructor and stores a copy of the ostream instance as a member variable. Advantages: The typical idiom for most variables passed in the constructor. Disadvantages: For correctness, this requires a semantically correct copy constructor which is very difficult, and often impossible, to write for streams.
  2. OstreamXmlWriter is passed a reference (pointer) to the ostream instance in its constructor and stores a reference (pointer) to the ostream instance as a member variable. Advantages: Relatively simple. Disadvantages: OstreamXmlWriter becomes implicitly tied to the lifetime of the passed object, which means that a user must be sure that OstreamXmlWriter is destroyed before the ostream instance is. Code such as stringstream* ss = new stringstream(); XmlWriter w(ss); delete ss; w.WriteStartElement("blah"); may result in hard-to-find bugs.
  3. OstreamXmlWriter is passed a smart pointer object (e.g. std::auto_ptr, boost::shared_ptr) which points to the ostream instance in its constructor and stores a copy of the smart pointer object as a member variable. Advantages: Lifetime issues are handled correctly. Disadvantages: The ostream instance must be constructed on the heap and never the stack. We expose a dependency on a smart pointer implementation that users probably shouldn’t care about. (Alternative: Take a heap-constructed ostream* in the constructor, store as a smart pointer member variable. However, what if a stack-constructed ostream is passed?)</li
  4. OstreamXmlWriter takes a reference to the ostream instance as an extra parameter for every XML writing function. Advantages: Parallels operator<<, no lifetime issues. Disadvantages: Breaks IXmlWriter-as-interface.

Based on these observations, I decided to go with (2). Here’s the new test case:

std::stringstream ss;
OstreamXmlWriter xmlWriter(ss, StringXmlWriter::Formatting_Indented);

xmlWriter.WriteComment("comment");
xmlWriter.WriteStartElement("root");
  xmlWriter.WriteElementString("child", "value");
  xmlWriter.WriteComment("comment");
  xmlWriter.WriteStartElement("child");
    xmlWriter.WriteAttributeString("att", "value");
  xmlWriter.WriteEndElement();
  xmlWriter.WriteStartElement("child");
    xmlWriter.WriteStartElement("child");
      xmlWriter.WriteStartElement("child");
xmlWriter.WriteEndDocument();

// ss.str() should equal (whitespace is important):
// <!--comment-->
// <root>
//   <child>value</child>
//   <!--comment-->
//   <child att="value"/>
//   <child>
//     <child>
//       <child/>
//     </child>
//   </child>
// </root>

Because the source code is starting to get unwieldy (chorus: Too late!), I have linked to the source code files rather than insert the source code in-line with the post. Here’s the latest source code:

Unfortunately, the source code for this post has been lost.