views:

113

answers:

4

Hi

I have a question about how to catch the exception in the initialization list.

For example, we have a class Foo derived from Bar

class Foo {

public:
Foo(int i) {throw 0; }

}

class Bar : public Foo{

public:

Bar() : Foo(1) {}

}
+1  A: 

I believe this should be caught by the procedure creating the object.

Spencer Ruport
+6  A: 

I think the syntax is like this (even though it's better to catch such things in the caller. And what are you going to do once you caught it?)

Bar::Bar()
try
  : Foo(1)
{
}
catch( const SomeException &e )
{
}
Arkadiy
Whoa, that is some weird-looking code.
Michael Myers
Note that this can't be used to ignore the exception. If the `catch` block doesn't throw an exception on it's own, the original exception is automatically rethrown (See the linked GOTW for details).
sth
@sth: sure it can, just `return`.
Potatoswatter
@Potatoswatter, no it can't. You can't even `return;` in the body of such a `catch` block for a ctor-initializer, as far as i know (as opposed to the catch block of other function try blocks).
Johannes Schaub - litb
@Johannes: hey, you're right, §15.3/15. Furthermore you can't attempt to perform initialization: "Referring to any non-static member or base class of an object in the handler for a function-try-block of a constructor or destructor for that object results in undefined behavior." That kinda sucks!
Potatoswatter
@Potatoswatter: It doesn't suck, there is just no object you could refer to at that point.
Georg Fritzsche
@gf: that sounds a bit strong. You could have nothrow guarantees on all but the last-initialized base/nonstatic member, and be certain they're valid. Granted that a more accommodating language spec wouldn't be very easy, or particularly useful.
Potatoswatter
@Potatos, so when the last-initialized member constructor throws, what are you supposed to do in your catch? You can't "repair" it, since the object in question would have done it itself if it could (it certainly has more knowledge about itself). You can just resignate and let the exception escape. So what would it buy you if you could access the other members? Notice that the destructors of the other members are called automatically if a later initialized member throws. So everything is cleaned nicely.
Johannes Schaub - litb
@Johannes: We can suppose that the throwing object may be inessential. Alternately, knowing the partially-constructed state could be useful for debugging output. I think it's probably easier to implement running the catch block after previously-initialized members are destroyed rather than destroy them after the rethrow, though. I'm not saying this is a big deal, but I can imagine frustration resulting.
Potatoswatter
+4  A: 

C++ has a mechanism for doing so, but it is rarely used. It is the function try block:

Bar::Bar()
try
  : Foo(1)
{
}
catch( Something )
{
}

See this classic gotw, which outlines why it should only be used to translate exceptions (e.g., exception type FooException becomes BarException).

Todd Gardner
Always catch a reference.
Potatoswatter
A: 

Consider replacing the troublesome instance with a boost::optional. Then you can defer its initialization into the body of the constructor.

Potatoswatter