Exceptional initialization list
November 30th, 2010 § 9 Comments
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.
Why would you enumerate an exception specification list? It’s a fundamentally broken “feature”.
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.
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
@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.
@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?
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&) { } } }Question: what plugin are you using to display code snippets? It looks really nice
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:
Where ‘X’ should be replaced with a ‘[‘.
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?