Re: Exceptions as smart pointers
David Abrahams wrote:
Then that's still not very useful, because the dtor might be called from
inside a catch block where the programmer needs non-throwing operations,
and in_stack_unwinding would be false.
Could you show the code, please?
struct File
{
// ...
~File(bool unwinding)
{
if (int err = close(this->x))
{
if (!unwinding)
throw couldnt_close(this->x, err);
}
}
os_file_handle x;
}
void rollback()
{
if ( logging_enabled)
{
File f(log);
f << "rolling_back\n";
}
// ...further rollback actions...
}
void f()
{
try
{
// ...
}
catch(...)
{
rollback();
raise;
}
}
I see no _additional_ problems here because File ctor can also throw
just like the File dtor in question.
The point is that if in_stack_unwinding==true then an exception from
the destructor *shall* lead to terminate(). No guess, this is a strong
guarantee.
Not *that* strong ;-)
I prefer really robust solutions ;)
In fact, as far as I can tell, uncaught_exception() will be
true during a dtor in exactly the same cases where your enhanced dtor's
unwinding argument will be true. If I'm wrong, please demonstrate how.
Please, consider the following code:
void f()
{
A a;
throw something;
}
A::~A(bool unwinding)
{
B b;
}
In this case A's unwinding==true but B's unwinding==false. Does
uncaught_exception() have the same semantics?
Okay. I'm not sure whether I agree. What is your argument against
Pimpl exception objects that contain nothing more than a shared_ptr?
That approach at least preserves the ability to catch base classes.
It complicates the life if you need to build the nested exception
chains. The chain of sh_ptr<BaseException> objects is really easy to get
if you always throw sh_ptr<BaseException>.
And it was the root of the problem!
Which problem?
The problem is the chain of nested exceptions.
Please refer to the head of this thread
http://groups.google.com/group/comp.lang.c++.moderated/msg/66a0c6484460d4ef
where I get the following output:
-----------------------------------8<-----------------------------------
Exception #1:
ders::Exception [..\tst_exc.cpp:127], message: Problems in f()
ders::Exception [..\tst_exc.cpp:156], message: Problems in g()
ExampleException [..\tst_exc.cpp:136], message: Hello from g()
Exception #2:
ders::Exception [..\tst_exc.cpp:127], message: Problems in f()
ders::Exception [..\tst_exc.cpp:156], message: Problems in g()
ders::StdExternException [..\tst_exc.cpp:154],
typeName="St12out_of_range", message: vector::_M_range_check
Exception #3:
ders::Exception [..\tst_exc.cpp:127], message: Problems in f()
ders::Exception [..\tst_exc.cpp:156], message: Problems in g()
ders::UnknExternException [..\tst_exc.cpp:154], typeName="unknown",
message: Unknown exception
Exception #4:
ders::UnknExternException [..\tst_exc.cpp:110], typeName="unknown",
message: Unknown exception
Non-empty exit message
-----------------------------------8<-----------------------------------
At the time, I tried to get portable and easy-to-use C++ exception
traces that somehow resemble my Java code. The direct solution is
sh_ptr<Exception>...
Is that the problem you're solving, then?
Yes, it is.
But it was discovered that the throw sh_ptr<BaseException> approach has
additional advantages too.
shException recatchException(mem_pool& mp, const FileLine& location)
{
try { throw; }
catch (shException she) {
return she;
}
catch (const std::exception& se) {
return newStdExternException(mp, location, se.what(),
typeid(se).name());
}
catch (...) {
return newUnknExternException(mp, location, "Unknown exception");
}
}
Okay. I'm not sure why newException isn't calling recatchException
instead, but at least now I understand what you're doing.
Prefer "one class (or function), one responsibility", you know ;)
--
With all respect, Sergey. http://ders.stml.net/
mailto : ders at skeptik.net
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]