Exceptional initialization list

Using the initialization list is very much encouraged in C++, and rightfully so - it has many benefits. But what happens if one of your members fails at initialization and actually throws an exception? Even worse: what happens if that member’s constructor throws an exception not in your exception specification list?

That’s what happened to me just the other day; I was using SWIG to wrap a C++ class to Python (by the way, SWIG is just plain awesome), and since exception specification causes wrapping of the exception classes as well, it’s a good idea to use that. So there I was, declaring my constructor to only throw instances of std::runtime_error.. Only to discover that one of my members (implemented elsewhere) could actually throw a const char*.

Luckily, I was familiar with the idea of catching exceptions raised within the initialization list, and that’s exactly what was needed to save the day. The required syntax is hereby presented:

struct myclass {
    myclass () throw(std::runtime_error)
        try
        : m_member("test") {
            // normal constructor code
        }
        catch (const char *err) {
            throw std::runtime_error(err);
        }

    private:
        someotherclass m_member;
};

There are of course some limitations on what you can do within the catch-block, the major one being that you must throw something; You cannot continue normal execution having failed initializing the object — if nothing is thrown when reaching the end of the catch-block, the caught exception is automatically re-thrown.

Extra details and more in-depth discussion of the mechanism can be found at GotW#66.

9 thoughts on “Exceptional initialization list

  1. Why would you enumerate an exception specification list? It’s a fundamentally broken “feature”.

  2. One note only, exception specifications are deprecated in upcoming C++ standard and for good reason. In current standard they are seen as a bad practice so you shouldn’t use them at all.

  3. The try-catch constructor is very handy though but VC provides a very neat extension allowing you to not throw exception.

    struct my
    {
     my()
     try : m_member("A")
     {
     }
     catch (exception const&)
     {
       return; // MS Extension, object is created without exception 
     }
    }
    

    Some points to mention:
    You should not use throw specification as it is declared as deprecated in C++0x and it doesn’t work as expected.

    And the last one, never throw types not derived from std::exception or your BaseException class :)

  4. @NN: Are you VC really behaves like that? Allowing a not-fully constructed object to live on?! Sounds very evil.

    Hopefully it’s the old v6 and not the never ones.

  5. @NN

    So what does that MS extension mean? That I’ll get a new object that potentially isn’t initialized?
    Can you give an example of where this is useful?

    1. Yes, that’s right.
      You can have object which is not fully initialized:

      #include <exception>
      #include <iostream>
      #include <string>
      
      bool throwException() { throw std::exception(); return true; }
      
      class standardStyle
      {
      public:
      	standardStyle()
      		try : b_(throwException())
      	{
      		s = "No Exception";
      	}
      	catch (std::exception const&)
      	{		
      	}
      
      	bool b_;
      	std::string s;
      };
      
      class vcExtension
      {
      public:
      	vcExtension()
      		try : s(), b(throwException()), i(1)
      		{
      			s = "1";
      		}
      		catch (std::exception const&)
      		{
      			s = "Caught Exception!";
      			return;
      		}
      
      	std::string s;
      	bool b;
      	int i;
      };
      
      
      int main()
      {
      	try
      	{
      		standardStyle st;
      	}
      	catch (std::exception const&)
      	{
      		// Object was not created...
      	}
      
      	// Object is created but only members before throw are initialized!
      	vcExtension vc;
      	
      	std::cout << vc.s << "n"; // Great !
      	std::cout << vc.i << "n"; // Not so good
      	
      	return 0;
      }
      

      Where it is useful ? It is useful, but not in that way of course ;)

      It is useful if you want to continue execution even if member constructor fails.
      So for this you should use boost::optional which solves the problem:

      class X
      {
       boost::optional<ThrowMemberConstructor> t;
      
      public:
       X() 
       {
        try
        {
         // Delayed construction
         v = boost::in_place(arg1, arg2);
        }
        catch(std::exception const&)
        {
        }
       }
      }
      
    1. Thanks :)

      That’s called “SyntaxHighlighter”, and you can get its details by pressing the rightmost question-mark button that pops at the top of the sourcecode section when you hover your mouse over it.
      I believe all blogs under wordpress.com have it by default (also within comments), and you can use it by writing the following:

      Xsourcecode language=”cpp”]
      // some code
      X/sourcecode]

      Where ‘X’ should be replaced with a ‘[‘.

  6. This is one of those things that prove that C++ can’t be learned. And by the way aren’t exception specifiers deprecated in C++0x?

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>