468,121 Members | 1,528 Online
Bytes | Developer Community
New Post

Home Posts Topics Members FAQ

Post your question to a community of 468,121 developers. It's quick & easy.

Exception in the constructor can't be caught?

Dear newsgroup,

In the following code, it looks as though the exception thrown in the
constructor is not caught properly. I get this output:

---- standard output ----
Base() constructor.
Exception in Base(): "Going down (B can't be
construced properly)!"
(the exception has now been dealt with).
main(): We got an exception while constructing B
that already should have been dealt with?
-------------------------
Here is the code:
---- Code ----
#include <iostream>
#include <stdexcept>
class Base
{
public:
Base()
try
{
std::cout << "Base() constructor.\n";
throw std::runtime_error("Going down (B can't be construced "
"properly)!");
}
catch(const std::exception& ex)
{
std::cout << "Exception in Base(): \""
<< ex.what()
<< "\"\n (the exception has now been dealt with).\n";
}
virtual ~Base()
{
std::cout << "~Base()\n";
}
};

int main()
{
try
{
Base B;
}
catch(const std::exception& ex)
{
std::cout << "main(): "
<<"We got an exception while constructing B\n"
" that already should have been dealt with?\n";
}
return 0;
}
---- End-of-Code ----

Anybody have an explanation to why the exception looks to have been
re-thrown?
Sincerely,
Peter Jansson
http://www.p-jansson.com/
http://peter.jansson.net/
Jul 31 '08 #1
11 1948
Peter Jansson wrote:
In the following code, it looks as though the exception thrown in the
constructor is not caught properly. I get this output:

[...]

class Base
{
public:
Base()
try
{
std::cout << "Base() constructor.\n";
throw std::runtime_error("Going down (B can't be construced "
"properly)!");
}
catch(const std::exception& ex)
{
std::cout << "Exception in Base(): \""
<< ex.what()
<< "\"\n (the exception has now been dealt with).\n";
}
virtual ~Base()
{
std::cout << "~Base()\n";
}
};

int main()
{
try
{
Base B;
}
catch(const std::exception& ex)
{
std::cout << "main(): "
<<"We got an exception while constructing B\n"
" that already should have been dealt with?\n";
}
return 0;
}
You can find a very detailed and insightful answer to your question
here: http://www.gotw.ca/gotw/066.htm

--
Christian Hackl
Jul 31 '08 #2
On Jul 31, 10:59*am, Christian Hackl <ha...@sbox.tugraz.atwrote:
Peter Jansson wrote:
In the following code, it looks as though the exception thrown in the
constructor is not caught properly. I get this output:
[...]
class Base
{
* * public:
* * * *Base()
* * * * * try
* * * * * {
* * * * * * *std::cout << "Base() constructor.\n";
* * * * * * *throw std::runtime_error("Going down (B can't be construced "
* * * * * * * * * *"properly)!");
* * * * * }
* * * *catch(const std::exception& ex)
* * * *{
* * * * * std::cout << "Exception in Base(): \""
* * * * * * *<< ex.what()
* * * * * * * * << "\"\n * *(the exception has now been dealt with).\n";
* * * *}
* * * *virtual ~Base()
* * * *{
* * * * * std::cout << "~Base()\n";
* * * *}
};
int main()
{
* * try
* * {
* * * *Base B;
* * }
* * catch(const std::exception& ex)
* * {
* * * *std::cout << "main(): "
* * * * * <<"We got an exception while constructing B\n"
* * * * * * *" * *that already should have been dealtwith?\n";
* * }
* * return 0;
}

You can find a very detailed and insightful answer to your question
here:http://www.gotw.ca/gotw/066.htm

--
Christian Hackl- Hide quoted text -

- Show quoted text -
Interesting that the article contains these statements:

Q: When does an object's lifetime end?

A: When its destructor begins. That is, control reaches
the beginning of the destructor body.
I disagree with the above. If the object no longer exists
starting from the beginning of the destructor body, then
the destructor could not access any of its internal fields.
If that were the case, the existence of the destructor
becomes useless.

The object MUST exist until the final statement of the
destructor is executed.
--
Fred Kleinschmidt

Jul 31 '08 #3
On Thu, 31 Jul 2008, Christian Hackl wrote:
You can find a very detailed and insightful answer to your question here:
http://www.gotw.ca/gotw/066.htm
Thank you, that article really cleared it all for me. Basically, the
answer to my question is the following quote from that article:

"What's less obvious, but clearly stated in the standard, is that if the
catch block does not throw (either rethrow the original exception, or
throw something new), and control reaches the end of the catch block of a
constructor or destructor, then the original exception is automatically
rethrown."

Sincerely,
Peter Jansson
http://www.p-jansson.com/
http://peter.jansson.net/
Jul 31 '08 #4
On Jul 31, 1:47*pm, Peter Jansson <webmas...@jansson.netwrote:
Dear newsgroup,

In the following code, it looks as though the exception thrown in the
constructor is not caught properly. I get this output:

---- standard output ----
Base() constructor.
Exception in Base(): "Going down (B can't be
construced properly)!"
* * *(the exception has now been dealt with).
main(): We got an exception while constructing B
* * *that already should have been dealt with?
-------------------------

Here is the code:

---- Code ----
#include <iostream>
#include <stdexcept>
class Base
{
* * public:
* * * *Base()
* * * * * try
* * * * * {
* * * * * * *std::cout << "Base() constructor.\n";
* * * * * * *throw std::runtime_error("Going down (B can't be construced "
* * * * * * * * * *"properly)!");
* * * * * }
* * * *catch(const std::exception& ex)
* * * *{
* * * * * std::cout << "Exception in Base(): \""
* * * * * * *<< ex.what()
* * * * * * * * << "\"\n * *(the exception has now been dealt with).\n";
* * * *}
* * * *virtual ~Base()
* * * *{
* * * * * std::cout << "~Base()\n";
* * * *}

};

int main()
{
* * try
* * {
* * * *Base B;
* * }
* * catch(const std::exception& ex)
* * {
* * * *std::cout << "main(): "
* * * * * <<"We got an exception while constructing B\n"
* * * * * * *" * *that already should have been dealt with?\n";
* * }
* * return 0;}

---- End-of-Code ----

Anybody have an explanation to why the exception looks to have been
re-thrown?
It is caught and rethrown, as mandated by the standard (cf. the GOTW
article mentioned above). If you don't want it to be rethrown, put
your try-catch block *in* the constructor body rather than using a
function-try-block *as* the body:

Base::Base()
{ // Note this brace
try
{
std::cout << "Base() constructor.\n";
throw std::runtime_error("Going down (B can't be construced "
"properly)!");
}
catch(const std::exception& ex)
{
std::cout << "Exception in Base(): \""
<< ex.what()
<< "\"\n (the exception has now been dealt with).
\n";
}
} // Note this brace

Cheers! --M
Jul 31 '08 #5
On Thu, 31 Jul 2008, Fred wrote:

[...]
I disagree with the above. If the object no longer exists
starting from the beginning of the destructor body, then
the destructor could not access any of its internal fields.
If that were the case, the existence of the destructor
becomes useless.

The object MUST exist until the final statement of the
destructor is executed.
--
Fred Kleinschmidt
I can not think of any situation where it is interesting to know wether an
object exist or not during it's destruction.

Sincerely,
Peter Jansson
http://www.p-jansson.com/
http://peter.jansson.net/
Jul 31 '08 #6
On Thu, 31 Jul 2008, mlimber wrote:
It is caught and rethrown, as mandated by the standard (cf. the GOTW
article mentioned above). If you don't want it to be rethrown, put
your try-catch block *in* the constructor body rather than using a
function-try-block *as* the body:
Yes, that works ok as long as Base is a "first base" class and not
actually derived from some sub base class that throws something during
it's oncstruction.

Sincerely,
Peter Jansson
http://www.p-jansson.com/
http://peter.jansson.net/
Jul 31 '08 #7
On 31 Jul., 20:33, Fred <fred.l.kleinschm...@boeing.comwrote:
On Jul 31, 10:59*am, Christian Hackl <ha...@sbox.tugraz.atwrote:


Peter Jansson wrote:
In the following code, it looks as though the exception thrown in the
constructor is not caught properly. I get this output:
[...]
class Base
{
* * public:
* * * *Base()
* * * * * try
* * * * * {
* * * * * * *std::cout << "Base() constructor.\n";
* * * * * * *throw std::runtime_error("Going down (B can't be construced "
* * * * * * * * * *"properly)!");
* * * * * }
* * * *catch(const std::exception& ex)
* * * *{
* * * * * std::cout << "Exception in Base(): \""
* * * * * * *<< ex.what()
* * * * * * * * << "\"\n * *(the exception has now been dealt with).\n";
* * * *}
* * * *virtual ~Base()
* * * *{
* * * * * std::cout << "~Base()\n";
* * * *}
};
int main()
{
* * try
* * {
* * * *Base B;
* * }
* * catch(const std::exception& ex)
* * {
* * * *std::cout << "main(): "
* * * * * <<"We got an exception while constructing B\n"
* * * * * * *" * *that already should have been dealt with?\n";
* * }
* * return 0;
}
You can find a very detailed and insightful answer to your question
here:http://www.gotw.ca/gotw/066.htm
--
Christian Hackl- Hide quoted text -
- Show quoted text -

Interesting that the article contains these statements:

* *Q: When does an object's lifetime end?

* *A: When its destructor begins. That is, control reaches
* * * the beginning of the destructor body.

I disagree with the above. If the object no longer exists
starting from the beginning of the destructor body, then
the destructor could not access any of its internal fields.
If that were the case, the existence of the destructor
becomes useless.

The object MUST exist until the final statement of the
destructor is executed.
No, this is not correct. The initial fields (and base objects) that
get fully constructed will get destructed, but the (nonexisting)
object will not - and this naturally is as it should be.

/Peter
Jul 31 '08 #8
On 2008-07-31 14:55:12 -0400, Peter Jansson <we*******@jansson.netsaid:
On Thu, 31 Jul 2008, mlimber wrote:
>It is caught and rethrown, as mandated by the standard (cf. the GOTW
article mentioned above). If you don't want it to be rethrown, put
your try-catch block *in* the constructor body rather than using a
function-try-block *as* the body:

Yes, that works ok as long as Base is a "first base" class and not
actually derived from some sub base class that throws something during
it's oncstruction.
Exactly. If the base subobject's constructor throws an exception,
there's nothing sensible that the derived type's constructor can do.

--
Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com) Author of "The
Standard C++ Library Extensions: a Tutorial and Reference
(www.petebecker.com/tr1book)

Jul 31 '08 #9
On Jul 31, 8:33 pm, Fred <fred.l.kleinschm...@boeing.comwrote:
On Jul 31, 10:59 am, Christian Hackl <ha...@sbox.tugraz.atwrote:
[...]
here:http://www.gotw.ca/gotw/066.htm
Interesting that the article contains these statements:
Q: When does an object's lifetime end?
A: When its destructor begins. That is, control reaches
the beginning of the destructor body.
I disagree with the above.
Then you disagree with the C++ standard, because that's what the
standard says.
If the object no longer exists starting from the beginning of
the destructor body, then the destructor could not access any
of its internal fields. If that were the case, the existence
of the destructor becomes useless.
There are a number of things you can do with an object in the
process of being constructed or destructed. But the C++
standard is clear; the lifetime of the object has ceased.

From the standard's point of view, this is mainly important for
stack unwinding during exception handling. The destructor is
called only on objects whose lifetime has not yet ended; once
you enter the destructor (and until you leave the constructor),
the destructor of that object will not be called. (But
destructors of fully constructed sub-objects will be.)
The object MUST exist until the final statement of the
destructor is executed.
The underlying raw memory must exsit, and the sub-objects must
exist, but the object itself, no.

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Aug 1 '08 #10
In article
<ef**********************************@a1g2000hsb.g ooglegroups.com>, James
Kanze <ja*********@gmail.comwrote:
On Jul 31, 8:33 pm, Fred <fred.l.kleinschm...@boeing.comwrote:
On Jul 31, 10:59 am, Christian Hackl <ha...@sbox.tugraz.atwrote:
[...]
here:http://www.gotw.ca/gotw/066.htm
Interesting that the article contains these statements:

Q: When does an object's lifetime end?

A: When its destructor begins. That is, control reaches
the beginning of the destructor body.
I disagree with the above.
...
The object MUST exist until the final statement of the
destructor is executed.

The underlying raw memory must exsit, and the sub-objects must
exist, but the object itself, no.
It sounds like you're saying that this yields undefined behavior:

struct S
{
virtual void f() { cout << typeid (*this).name(); }
void g() { f(); }
virtual ~S() { g(); }
};

int main() { S s; }

How could the S object's lifetime have ended, yet virtual functions still
work? I obviously need to re-read relevant sections of the standard, but
I'm sure I'm not the only one who finds the above statements surprising,
even if my example program doesn't yield any undefined behavior.
Aug 1 '08 #11
On Aug 1, 5:25 pm, blargg....@gishpuppy.com (blargg) wrote:
In article
<ef422ec9-84d3-4185-9034-752b62d1b...@a1g2000hsb.googlegroups.com>, James
Kanze <james.ka...@gmail.comwrote:
On Jul 31, 8:33 pm, Fred <fred.l.kleinschm...@boeing.comwrote:
On Jul 31, 10:59 am, Christian Hackl <ha...@sbox.tugraz.atwrote:
[...]
here:http://www.gotw.ca/gotw/066.htm
Interesting that the article contains these statements:
Q: When does an object's lifetime end?
A: When its destructor begins. That is, control reaches
the beginning of the destructor body.
I disagree with the above.
...
The object MUST exist until the final statement of the
destructor is executed.
The underlying raw memory must exsit, and the sub-objects must
exist, but the object itself, no.
It sounds like you're saying that this yields undefined
behavior:
struct S
{
virtual void f() { cout << typeid (*this).name(); }
void g() { f(); }
virtual ~S() { g(); }
};
int main() { S s; }
Now where did I say that?
How could the S object's lifetime have ended, yet virtual
functions still work?
Because the standard says that they do. That's really the only
answer I can give. The standard says that for everything
concerning RTTI (dynamic_cast, typeid and virtual function call
resolution), the "object" (whose lifetime has ended) acts as if
it had the type of the destructor being executed.
I obviously need to re-read relevant sections of the standard,
but I'm sure I'm not the only one who finds the above
statements surprising, even if my example program doesn't
yield any undefined behavior.
I'll admit that the standard's wording isn't always the most
intuitive. I think the problem is that it is trying to use a
binary state (alive/dead) for a situation that isn't binary.
The object's "lifetime" starts when the most derived constructor
is finished, and ends when the most derived destructor starts
(see §3.8), but a not yet alive object (or an already dead
object) definitely has certain properties of the object (and not
of just raw memory). Section 3.8 basically says that there are
only a limited set of things that you can do outside of the
lifetime, but in practice, some of them just don't make sense:
according to §3.8, for example, you can't convert a a pointer to
the object to a pointer to the base class. Which taken
literally would mean that you can't call a member function of a
base class from the constructor, because that implies an
implicit conversion of the this pointer to a pointer to the base
class. Note, however, that there are special rules which are in
effect in constructors and destructors, and that some things
that seem like the obviously should work are actually undefined
behavior (and in one case I had, didn't work).

--
James Kanze (GABI Software) email:ja*********@gmail.com
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
Aug 1 '08 #12

This discussion thread is closed

Replies have been disabled for this discussion.

Similar topics

4 posts views Thread by Barry Mossman | last post: by
40 posts views Thread by Kevin Yu | last post: by
9 posts views Thread by Claudio Di Flumeri | last post: by
3 posts views Thread by Neelesh Bodas | last post: by
10 posts views Thread by junw2000 | last post: by
10 posts views Thread by Rahul | last post: by
18 posts views Thread by didacticone | last post: by
By using this site, you agree to our Privacy Policy and Terms of Use.