Posted by: rmn on: 30/11/2010
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 ofcouse 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 rethrown.
Extra details and more in-depth discussion of the mechanism can be found at GotW#66.
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
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?
01/12/2010 at 00:14
Why would you enumerate an exception specification list? It’s a fundamentally broken “feature”.