Topic: Catching exceptions in constructors


Author: maxtal@Physics.usyd.edu.au (John Max Skaller)
Date: 1995/08/08
Raw View
In article <3vr94j$hvm@wl10.whitelight.com>,
Floyd McWilliams  <floyd@whitelight.com> wrote:
>
>Multiple inheritence and exceptions don't seem to mix nicely.

 Why not?

 IMHO they do, if you do it right. Just beware of the
Standard Library exception classes, which do not.

--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189





Author: Floyd McWilliams <floyd@whitelight.com>
Date: 1995/08/02
Raw View
marnold@netcom.com (Matt Arnold) wrote:
>Etay Bogner <ebogner@ird.scitex.com> writes:

[Etay talks about a C++ problem: one can't catch an exception thrown from an
 initializer of a ctor:

  Foo::Foo(int x) bar(x) // If exception thrown initializing bar, too bad
  { ... }
]


>Exactly why do you want to catch an exception in a constructor
>anyway?  Rathre, shouldn't the creator of the object be prepared to
>handle any exceptions thrown during intialization?
>
..
>
>The creator of the object (the thing calling new) should handle any
>exceptions thrown during construction.  Exactly what would you do in
>the constructor body if you _were_ able to catch an exception thrown
>in the initializer list?  Delete the object (already taken care of by
>the language, BTW)?  "Return" NULL somehow?  Throw another exception?
>What?
>
>It just doesn't seem to make any sense to want to do this.

[ Sig with bar code deleted.  Unlike Maggie Simpson, Matt is fully prepared to
  be run through the scanner at his local supermarket. ]

What if the process of constructing the object involves details that the ctor
caller shouldn't know about?  And what if the details are reflected in the
exception that was thrown during initialization?  To wit:

class Bar
{
  Bar(int x) throw BarFailed;
  ...
};

class Foo
{
private:
  Bar bar;
  ...
};

Foo::Foo(int arg) bar(arg)
{
}

bar is used privately to implement a Foo.  Bar::Bar() throws a BarFailed exception.
We could make the Foo::Foo() caller catch the BarFailed -- but what if we change
the implementation later:

class Fred { ... };

class Foo
{
private:
  Fred fred;
  ...
};

Foo::Foo(int arg) fred(arg)
{
  ...
}

Fred::Fred() wants to throw FredFailed when it fails.  But it can't without
blowing up all the Foo users.  So fred() has to throw a BarFailed.  Not a
good idea.

It would be best if Foo::Foo() could catch exceptions and throw something
generic, like FooFailed.

To forestall argument, I do not agree that bar() and fred() should throw
generic exceptions.  It's not their job to be generic.  They probably don't
know anything about each other or about Foo.

Class member initialization is a botch.  It's got neat and compact syntax,
but it cannot handle all the burdens it assumes.  I haven't even mentioned the
problem of argument checking.  What if Foo()'s arg were invalid?  Or a pointer
that was passed NULL?

-Floyd McWilliams
 floyd@whitelight.com







Author: immel@rapier.centerline.com (Mark Immel)
Date: 1995/08/03
Raw View
In article <3voi90$clm@wl10.whitelight.com> Floyd McWilliams <floyd@whitelight.com> writes:

   [Etay talks about a C++ problem: one can't catch an exception thrown from an
    initializer of a ctor:

The ANSI Committee has recently addressed this problem.  The following
is now in the grammar:

function-try-block:
  try ctor-initializer-opt function-body handler-seq

which allows you to write things like:

struct Foo {
  Bar b;
  Foo();
};

Foo::Foo() try b(3)
{
  cout << "A new Foo" << endl;
} catch (Exception& e) {
  cerr << "Oh, no..." << endl;
  throw;
}

Of course, I don't know of any compiler that accepts this yet.  And I
may have the syntax slightly wrong, for which I apologize.

--
Mark Immel
immel@centerline.com
(202) 393-7833 (office)
(617) 498-3409 (voicemail)



--
My opinions are not necessarily those of my employer.






Author: rad6938@gemini.tntech.edu (Rad)
Date: 1995/08/03
Raw View
In article <3voi90$clm@wl10.whitelight.com>, Floyd McWilliams <floyd@whitelight.com> writes:
>marnold@netcom.com (Matt Arnold) wrote:
>>Etay Bogner <ebogner@ird.scitex.com> writes:
>
>[Etay talks about a C++ problem: one can't catch an exception thrown from an
> initializer of a ctor:
>...
>
>What if the process of constructing the object involves details that the ctor
>caller shouldn't know about?  And what if the details are reflected in the
>exception that was thrown during initialization?  To wit:
>
>class Bar
>{
>  Bar(int x) throw BarFailed;
>  ...
>};
>
>class Foo
>{
>private:
>  Bar bar;
>  ...
>};
>
>Foo::Foo(int arg) bar(arg)
>{
>}
>
>bar is used privately to implement a Foo.  Bar::Bar() throws a BarFailed exception.
>We could make the Foo::Foo() caller catch the BarFailed -- but what if we change
>the implementation later:
>
>class Fred { ... };
>
>class Foo
>{
>private:
>  Fred fred;
>  ...
>};
>
>Foo::Foo(int arg) fred(arg)
>{
>  ...
>}
>
>Fred::Fred() wants to throw FredFailed when it fails.  But it can't without
>blowing up all the Foo users.  So fred() has to throw a BarFailed.  Not a
>good idea.
>
>It would be best if Foo::Foo() could catch exceptions and throw something
>generic, like FooFailed.
>
>To forestall argument, I do not agree that bar() and fred() should throw
>generic exceptions.  It's not their job to be generic.  They probably don't
>know anything about each other or about Foo.
>
>Class member initialization is a botch.  It's got neat and compact syntax,
>but it cannot handle all the burdens it assumes.  I haven't even mentioned the
>problem of argument checking.  What if Foo()'s arg were invalid?  Or a pointer
>that was passed NULL?

This seems to be more appropriately handled using inheritance in your exception
classes.  If you define a FooFailed class derived from possible exceptions that
could cause Foo to fail you should be able to catch all those exceptions using
the derived class FooFailed.  When you change Foo's constructor later, you
only need to change the FooFailed derivations in order to continue isolating
the user from having to catch individual exception classes.

----------------------------------------------------------------------------
 Richard Deken                   Graduate student in electrical engineering
 PGP public key available      Tennessee Technological University
 Internet: rad6938@gemini.tntech.edu        Cookeville, TN, USA





Author: Floyd McWilliams <floyd@whitelight.com>
Date: 1995/08/03
Raw View
rad6938@gemini.tntech.edu (Rad) wrote:
>In article <3voi90$clm@wl10.whitelight.com>, Floyd McWilliams <floyd@whitelight.com> writes:
>>marnold@netcom.com (Matt Arnold) wrote:
>>>Etay Bogner <ebogner@ird.scitex.com> writes:
>>
>>[Etay talks about a C++ problem: one can't catch an exception thrown from an
>> initializer of a ctor:
>>...
>>
>>What if the process of constructing the object involves details that the ctor
>>caller shouldn't know about?  And what if the details are reflected in the
>>exception that was thrown during initialization?  To wit:
>>
>>class Bar
>>{
>>  Bar(int x) throw BarFailed;
>>  ...
>>};
>>
>>class Foo
>>{
>>private:
>>  Bar bar;
>>  ...
>>};
>>
>>Foo::Foo(int arg) bar(arg)
>>{
>>}
>>
>>bar is used privately to implement a Foo.  Bar::Bar() throws a BarFailed exception.
>>We could make the Foo::Foo() caller catch the BarFailed -- but what if we change
>>the implementation later:
>>
>>class Fred { ... };
>>
>>class Foo
>>{
>>private:
>>  Fred fred;
>>  ...
>>};
>>
>>Foo::Foo(int arg) fred(arg)
>>{
>>  ...
>>}
>>
>>Fred::Fred() wants to throw FredFailed when it fails.  But it can't without
>>blowing up all the Foo users.  So fred() has to throw a BarFailed.  Not a
>>good idea.
>>
>>It would be best if Foo::Foo() could catch exceptions and throw something
>>generic, like FooFailed.
>>
>>To forestall argument, I do not agree that bar() and fred() should throw
>>generic exceptions.  It's not their job to be generic.  They probably don't
>>know anything about each other or about Foo.
>>
>>Class member initialization is a botch.  It's got neat and compact syntax,
>>but it cannot handle all the burdens it assumes.  I haven't even mentioned the
>>problem of argument checking.  What if Foo()'s arg were invalid?  Or a pointer
>>that was passed NULL?
>
>This seems to be more appropriately handled using inheritance in your exception
>classes.  If you define a FooFailed class derived from possible exceptions that
>could cause Foo to fail you should be able to catch all those exceptions using
>the derived class FooFailed.  When you change Foo's constructor later, you
>only need to change the FooFailed derivations in order to continue isolating
>the user from having to catch individual exception classes.
>
>----------------------------------------------------------------------------
> Richard Deken                   Graduate student in electrical engineering
> PGP public key available      Tennessee Technological University
> Internet: rad6938@gemini.tntech.edu        Cookeville, TN, USA

But what happens when a Foo user defines HIS OWN inheritence of the exception
classes?

class UserEx : public BarFailed, public FredFailed, public SomeoneElseFailed
{
..
};

void FooUser()
{
  try {
    Foo aFoo(7); // Throws BarFailed (but FooUser() thinks it's FooFailed)
    UserClass user("hello"); // Throws BarFailed
  }
  catch(UserEx &err) { ... }
  catch(FooFailed &err) { ... }
}

aFoo throws a BarFailed in Foo::Foo().  I believe that the exception is caught
in catch(UserEx &err) (just because it's first), or where it is caught is
undefined.  (I am not ARMed today. :-) )

Multiple inheritence and exceptions don't seem to mix nicely.

-Floyd McWilliams
 floyd@whitelight.com








Author: schuenem@informatik.tu-muenchen.de (Ulf Schuenemann)
Date: 1995/07/31
Raw View
In article <3v69t3$sj1$1@mhade.production.compuserve.com>, Randy T. Merkel <73537.3705@CompuServe.COM> writes:
[..]
|> class X {
|>  Y y;
|> public:
|>  X (const Y& y_) : y (y_) {}
|> // ...
|> };

Use a function-try-block (CD [except] 15.1,1(grammar) and ,3(semantics))
[ I've no experience with it but following the grammar it should look like: ]

 class X {
  Y y;
 public:
  X (const Y& y_)
  try : y (y_)
  { /* normal body */ }
  catch(...) { /* ... */ }
 // ...
 };

AFAI can remember a comment, handling exceptions of ctor-initializers
was the main reason to introduce function-try-blocks.


Ulf Schuenemann

--------------------------------------------------------------------
Ulf Sch   nemann
Fakult   t f   r Informatik, Technische Universit   t M   nchen, Germany.
email: schuenem@informatik.tu-muenchen.de
WWW:   http://www.informatik.tu-muenchen.de/cgi-bin/nph-gateway/hphalle2/~schuenem/index.html
...there is only one way to "skin a C+@"...:)  -- Jim Fleming





Author: rjl@f111.iassf.easams.com.au (Rohan LENARD)
Date: 1995/07/30
Raw View
In article <3v69t3$sj1$1@mhade.production.compuserve.com>,
Randy T. Merkel  <73537.3705@CompuServe.COM> wrote:
>Howdy one and all:
>
>How does one catch a exception within a constructor that may be
>thrown from an initializer list? For example I want to catch an
>exception thrown from y::Y (const Y& y_) below;
>

I can see two simple options:

1. Use a generator function -

  class X {
    Y y;
    X (const Y& y_) : y (y_) {}
  public:
    X* Generate() {
      try { return new X; } catch (...) { /* ... */ }
      return 0;
    };
  };

2.  Use another class to generate the X and deal with exceptions.  It can
    be used as a proxy for X (Note: Validity checking deliberately left out):

  class Z {
  public:
    Z() : pX(0) {
      try { pX = new X; } catch (...) { /* ... */ }
    };
    Z( const Z& toCopy ) : pX(0) {
      try { pX = new X(*toCopy.pX); } catch (...) { /* ... */ }
    };
    const Z& operator=( const Z& toCopy ) {
      try { *pX = *toCopy.pX; } catch (...) { /* ... */ }
    };
    ~Z()  { delete pX; }
    operator X& (); { return *pX; }
  private:
    X* pX;
  };

Regards,
 Rohan
--
----------------------------------------------------------------------------
rjl@iassf.easams.com.au | All quotes can be attributed to my automated quote
Rohan Lenard            | writing tool.  Yours for just $19.95; and if you
+61-2-367-4555          | call now you'll get a free set of steak knives ...





Author: itz@rahul.net (Ian T Zimmerman)
Date: 1995/07/30
Raw View
Distribution:

In article <3veqkv$5v5@f111.iassf.easams.com.au> rjl@f111.iassf.easams.com.au (Rohan LENARD) writes:

>
> In article <3v69t3$sj1$1@mhade.production.compuserve.com>,
> Randy T. Merkel  <73537.3705@CompuServe.COM> wrote:
> >Howdy one and all:
> >
> >How does one catch a exception within a constructor that may be
> >thrown from an initializer list? For example I want to catch an
> >exception thrown from y::Y (const Y& y_) below;
> >
>
> I can see two simple options:
>
> 1. Use a generator function -
>
>   class X {
>     Y y;
>     X (const Y& y_) : y (y_) {}
>   public:
>     X* Generate() {
>       try { return new X; } catch (...) { /* ... */ }
>       return 0;
>     };
>   };
>
> 2.  Use another class to generate the X and deal with exceptions.  It can
>     be used as a proxy for X (Note: Validity checking deliberately left out):
>
>   class Z {
>   public:
>     Z() : pX(0) {
>       try { pX = new X; } catch (...) { /* ... */ }
>     };
>     Z( const Z& toCopy ) : pX(0) {
>       try { pX = new X(*toCopy.pX); } catch (...) { /* ... */ }
>     };
>     const Z& operator=( const Z& toCopy ) {
>       try { *pX = *toCopy.pX; } catch (...) { /* ... */ }
>     };
>     ~Z()  { delete pX; }
>     operator X& (); { return *pX; }
>   private:
>     X* pX;
>   };
>

How does either of these deal with the memory that will have been
allocated for the X object by the time Y::Y() throws?
--
Ian T Zimmerman            +-------------------------------------------+
P.O. Box 13445             I    With so many executioners available,   I
Berkeley, California 94712 I suicide is a really foolish thing to do.  I
USA  <itz@rahul.net>       +-------------------------------------------+





Author: Etay Bogner <ebogner@ird.scitex.com>
Date: 1995/07/30
Raw View
This Q is VERY good.

The problem is that the answers I saw so far were NOT complete, since
they didn't supply a full solution.

For example, there is a problem when trying to initialize objects, or
objects references, versus initialzing pointers.

"Generator Functions" are ugly and the use of another class is too
heavy. The memory allocated is no problem since once the exception is
thrown, one can check to see if the pointer is NOT nil, assuming that
you first assigned nil to it.

The only sub-correct solution, IMHO, is to use positional ( AKA
placement ) new, as follows :


references can't raise exceptions ( they are almost simply pointer
assignment, and by definition can't fail ), and pointers can be
initialized from within the constructor body without any problems, so
the only problem is with classes ( objects ) as members.

class X {
 B  mB; // the only problem is classes as members.
 public :
  X::X(B& b); // just a simple example.
 };

Let's assume that B's copy constructor can raise an exception.
Also, B MUST have a constructor which will NOT fail for sure ( this is
the only thing I require ).
I usually use a special empty constructor with an enumerator as a
parameter, just as P.J Plauger initializes the iostream classes.

Something like :

class B {
 public :
  enum _Uninitialized {_Noinit};
  B(_Uninitialized) {} // a do-nothing constructor
 };

So :

X::X(B& b) : mB(B::_Noinit) {
 try {
  new(&mB) B(b); // activate the B's copy constructor ON mB position.
  }
 catch (...) {
  // catch whatever is thrown
  }
 }

But, then again, this is a problem in the lang, but I see no other way
to overcome it.

I guess that in such a case, one's better off using a pointer ...

-- Etay Bogner,
-- ebogner@ird.scitex.com ( OLD ),
-- Etay_Bogner@mail.stil.scitex.com,
-- Scitex Corp.
-- Israel.







Author: marnold@netcom.com (Matt Arnold)
Date: 1995/07/30
Raw View
Etay Bogner <ebogner@ird.scitex.com> writes:

>This Q is VERY good.

>The problem is that the answers I saw so far were NOT complete, since
>they didn't supply a full solution.

>For example, there is a problem when trying to initialize objects, or
>objects references, versus initialzing pointers.

>"Generator Functions" are ugly and the use of another class is too
>heavy. The memory allocated is no problem since once the exception is
>thrown, one can check to see if the pointer is NOT nil, assuming that
>you first assigned nil to it.

>The only sub-correct solution, IMHO, is to use positional ( AKA
>placement ) new, as follows :


>references can't raise exceptions ( they are almost simply pointer
>assignment, and by definition can't fail ), and pointers can be
>initialized from within the constructor body without any problems, so
>the only problem is with classes ( objects ) as members.

>class X {
> B  mB; // the only problem is classes as members.
> public :
>  X::X(B& b); // just a simple example.
> };

>Let's assume that B's copy constructor can raise an exception.
>Also, B MUST have a constructor which will NOT fail for sure ( this is
>the only thing I require ).
>I usually use a special empty constructor with an enumerator as a
>parameter, just as P.J Plauger initializes the iostream classes.

>Something like :

>class B {
> public :
>  enum _Uninitialized {_Noinit};
>  B(_Uninitialized) {} // a do-nothing constructor
> };

>So :

>X::X(B& b) : mB(B::_Noinit) {
> try {
>  new(&mB) B(b); // activate the B's copy constructor ON mB position.
>  }
> catch (...) {
>  // catch whatever is thrown
>  }
> }

>But, then again, this is a problem in the lang, but I see no other way
>to overcome it.

>I guess that in such a case, one's better off using a pointer ...

Exactly why do you want to catch an exception in a constructor
anyway?  Rathre, shouldn't the creator of the object be prepared to
handle any exceptions thrown during intialization?

Speaking only of the problem of somehow catching the exceptions
thrown by the constructors of embedded classes, why is it good to
wind up in a exception handler inside your constructor body when the
object has been only partially constructed? (ie, one of its embedded
classes has failed to intialize and some others may have not even
begun to!).  This seems like a very dangerous situation to allow and
it would completely bend the rules of C++ object initialization:  the
constructor for an object is not called until all of its base classes
and embedded objects have been successfully constructed first.

The creator of the object (the thing calling new) should handle any
exceptions thrown during construction.  Exactly what would you do in
the constructor body if you _were_ able to catch an exception thrown
in the initializer list?  Delete the object (already taken care of by
the language, BTW)?  "Return" NULL somehow?  Throw another exception?
What?

It just doesn't seem to make any sense to want to do this.

-------------------------------------------------------------------------
Matt Arnold                       |        | ||| | |||| |  | | || ||
marnold@netcom.com                |        | ||| | |||| |  | | || ||
Boston, MA                        |      0 | ||| | |||| |  | | || ||
617.389.7384 (h) 617.576.2760 (w) |        | ||| | |||| |  | | || ||
Windows C++ developer             |        | ||| 4 3 1   0 8 3 || ||
-------------------------------------------------------------------------








Author: Etay Bogner <ebogner@ird.scitex.com>
Date: 1995/07/30
Raw View
I totaly agree with all this, and I'm sorry I didn't say more than the
last line of my message ( which was "I guess that in such a case, one's
better off using a pointer ..." ).

The code I showed should be used just in some special case ( like
initializing the iostream objects, for example ).

Moreover, I shouldn't sent this code in the first place, since it is
actually just an academic solution ( I seem to look at some questions
like academic ones, and NOT practical ).

Again, this code is NOT for use :-)

-- Etay Bogner,
-- ebogner@ird.scitex.com ( OLD ),
-- Etay_Bogner@mail.stil.scitex.com,
-- Scitex Corp.
-- Israel.







Author: Randy T. Merkel <73537.3705@CompuServe.COM>
Date: 1995/07/26
Raw View
Howdy one and all:

How does one catch a exception within a constructor that may be
thrown from an initializer list? For example I want to catch an
exception thrown from y::Y (const Y& y_) below;

class X {
 Y y;
public:
 X (const Y& y_) : y (y_) {}
// ...
};

The only way that I have come up with is to;

class X {
    Y* y;
public:
    X (const Y& y_) {
        try { y = new Y (y_); } catch (...) { /* ... */ }
// ...
};

Is they a way with out using member pointers?
Randy...

--
Zymed Medical Instrumentation
Randy Merkel
rmerkel@ACM.org