I'm writing a drop-replacement for a container, and I'm trying to
get all the exception-guarantees in place. I'm currently writing
the clear method, and I want it to complete as much as possible,
and to always leave the container in a consistent state, even if
one of the destructors throw an exception. I also want to rethrow
the exception after I'm done cleaning, preferably without slicing.
This brings me to the question; when is an exception destructed?
Lets have a look at one attempt:
This is simplified for the example.
void container::clear()
{
bool had_exception = false;
std::exception* exp;
internal_set_empty(); // this cant throw
while( ! internal_done() )
{
try
{
internal_destruct_next(); // this might throw if T::~T() throws
}
catch( std::exception& e )
{
had_exception = true;
exp = &e;
}
}
if( had_exception )
throw *exp;
}
I expect this to fail badly, because the exception is probably destructed
when it is considered handled, and this doesn't technically rethrow.
Another attempt would be taking a copy of the exception, something that
I expect would slice.
Is there a way to extend the lifetime of the exception so I can rethrow
it later?
If possible, I would also like to be able to rethrow exceptions caught
via catch(...) .
even if one of the destructors throw an exception
Cannot be done. Destructors are nothrow for a reason- you can't recover from a throwing destructor. It's clear that you don't do anything to clean up the objects whose destructor threw- because how could you even try to do that- but that also means that you've just left them hanging around in a zombie state.
On your more specific question, you could use recursion to stay inside the catch's stack frame to try to keep deleting elements, or you could also use std::exception_ptr and friends in C++11 which are intended for transporting exceptions around.
The current usage to pass the exception to a caller is to rethrow it in the catch bloc. Assuming you have good reasons not to do it, the only other correct way is to use a std::exception_ptr. With a mere std::exception* there are high risk that the exception is destroyed and its memory deallocated before you can throw it again.
Standard C++ 2011 draft (n4296) says at 15.1 Throwing an exception § 4 : The exception
object is destroyed after either the last remaining active handler for the exception exits by any means other
than rethrowing, or the last object of type std::exception_ptr that refers to the exception object is
destroyed, whichever is later. In the former case, the destruction occurs when the handler exits, immediately
after the destruction of the object declared in the exception-declaration in the handler, if any. In the latter
case, the destruction occurs before the destructor of std::exception_ptr returns. The implementation
may then deallocate the memory for the exception object; any such deallocation is done in an unspecified
way (emphasize mine)
Related
What I mean is something like this:
//std::once_flag eptrFlag;
//std::exception_ptr eptr;
//...
try
{
// may throw exceptions
}
catch (...)
{
std::call_once(eptrFlag,
[&]()
{
//...
eptr = std::current_exception();
});
}
Is this undefined behavior, or is it safe?
I've read cppreferences that say:
If called during exception handling (typically, in a catch clause), captures the current exception object
I'm not sure what is during exception handling except a normal catch clause, does the closure of the catch block count as during exception handling?
Firstly, calling std::current_exception never causes undefined behaviour.
As for what is during exception handling, actually in the language standard exception handling also includes handling an uncaught exception (for instance, 18.1(7) of C++17 standard); for std::current_exception the actual condition is “during handling by an active handler an exception”;
An exception handler is active after its catch-clause argument is initialized and until the catch clause argument has just been destroyed.
If there is not currently handled by an active handler an exception, std:current_exception will return an empty std::exception_ptr.
Calling functions does not interrupt handling, but it is possible that handing by an active handler another exception will overlap the previous one.
As for, does the lambda function capturing context of the catch block count as during exception handling - in C++ for a lambda function it would be a matter of run-time conditions, it depends on when the function is called, after the handler is complete of before; in you case it is always before; if would called after, std:current_exception would return an empty std::exception_ptr.
As for using std::call_once here, it is not obvious from the piece of the code what exactly you want, but please note that an exception object and exception handling mechanism are thread-local. Even if the catch clause is run in multiple threads, it will never be working with the same exception unless both a reference to the same exception object was passed between threads and copy was not made while rethrowing.
It is implementation-defined whether std::current_exception and std::rethrow_exception make a copy, and you should just consider protection from simultaneous writing if do writing for the case they don’t copy, if don’t want to make you code be a mishmash checking whether it was copied or not and handling the case if not (though it is possible, there is no any sensible reason for that).
It is safe to call std::current_exception() anywhere within the scope of the catch block, even inside of nested function calls. But once the catch block exits, its exception object is no longer valid, unless captured by std::current_exception().
The following code terminates abnormally as no object is explicitly thrown. What is thrown by throw statement in the following code?
int main()
{
try{
cout<<"try";
throw ;
}
catch(...){
cout<<"catch";
}
return 0;
}
throw without an argument should only be used inside a catch statement, to rethrow the caught exception object. You code tries to use it outside the catch statement - instead you should pick a type to throw, if in doubt it's not unreasonable to start with std::runtime_error. For more options, see here. You can also throw your own types, but it's usually a good idea to derive them from one of the Standard-library provided types so client code has a better chance at specifying appropriate handling for all logically similar errors, rather than having to catch and handle them separately and being constantly updated for each new possible error.
FWIW, the Standard says in 15.1/9:
If no exception is presently being handled, executing a throw-expression with no operand calls std::terminate().
So very explicitly, the answer to "What is thrown..." is that no throwing is done, and std::terminate is called instead.
So the question is: "What happens when I throw outside a catch block?" The answer to this can be found in its documentation:
Rethrows the currently handled exception. Abandons the execution of the current catch block and passes control to the next matching exception handler (but not to another catch clause after the same try block: its compound-statement is considered to have been 'exited'), reusing the existing exception object: no new objects are made. This form is only allowed when an exception is presently being handled (it calls std::terminate if used otherwise). The catch clause associated with a function-try-block must exit via rethrowing if used on a constructor.
Emphasize mine.
I have a function foo that can throw a bar exception.
In another function I call foo but I have the ability to add some more detail to the bar exception if thrown. (I'd rather not pass such information as a parameter to foo as it doesn't really belong there due to the generic nature of that function.)
So I do this in the caller:
try {
foo();
} catch (bar& ex){
ex.addSomeMoreInformation(...);
throw;
}
Will throw re-throw the modified exception or do I need to use throw ex;? The latter would presumably take a value copy so I'd rather not do that. Would throw take a value copy too? I suspect it wouldn't.
(I'm aware I could verify but I'm concerned about stumbling on an unspecified or undefined construct so would like to know for sure).
Actually, the standard is very precise here. [except.handle]/17:
When the handler declares a reference to a non-constant object, any
changes to the referenced object are changes to the temporary object
initialized when the throw-expression was executed and will have
effect should that object be rethrown.
And [except.throw]/8:
A throw-expression with no operand rethrows the currently handled
exception (15.3).
C++11 §15.1/8:
” A throw-expression with no operand rethrows the currently handled exception (15.3). The exception is
reactivated with the existing temporary; no new temporary exception object is created.
In this case you should use throw to get the desired behavior...i.e throw would throw the modified exception as the exception was caught by reference.
Let me try to make difference between these throw explicit through examples:-
class exception
{
};
class MyException : public exception
{
};
void func()
{
try
{
throw MyException();
}
catch( exception& e )
{
//do some modification.
throw; //Statement_1
throw e; //Statement_2
}
}
Statment_1:-
What throw does is it just re-throws what the current exception is i.e it doesn't make further copies ( as was made when exception was thrown initially). So if you make any changes to the caught exception here...it would also be there in the caller routine.
Statement_2:-
This is throwing the "exception" which was originally caught as MyException i.e it would make the copy again. So, just forget about changes you made it won't even passes or*ginal exception to the caller. It throws "exception" to the caller routine.
Hope I am clear ( and RIGHT ON TRACK OF C++ STANDARD )enough...
throw (without an exception object) will rethrow the current exception. (must be inside catch block, otherwise std::terminate is called). Because you changed the reference of current exception object, you don't need to explicilty throw the object and throw re-throw the modified exception and no new temporary object is created.
according to this,throwing exceptions in c++ can be done in two ways:
throw expression: First, copy-initializes the exception object from expression (this may call the move constructor for rvalue expression, and the copy/move may be subject to copy elision), then transfers control to the exception handler with the matching type whose compound statement or member initializer list was most recently entered and not exited by this thread of execution.
throw: Rethrows the currently handled exception. Abandons the execution of the current catch block and passes control to the next matching exception handler (but not to another catch clause after the same try block: its compound-statement is considered to have been 'exited'), reusing the existing exception object: no new objects are made. This form is only allowed when an exception is presently being handled (it calls std::terminate if used otherwise). The catch clause associated with a function-try-block must exit via rethrowing if used on a constructor.
So to underline my answer, throw should be fine in your case.
A code which handles the exceptions well is called an exception safe code? Is this correct?
From here: https://codereview.stackexchange.com/a/9759/11619
You use lock/unlock pairs for the mutex. This is not exception safe.
So I would create an object that will do the lock in the constructor
and unlock in the destructor then use this to lock your mutexs. This
will make your code more exception safe.
class MutexLocker
{
pthread_mutex_t& mutex;
MutextLocker(pthread_mutex_t& mutex)
: mutex(mutex)
{
pthread_mutex_lock(&mutex);
}
~MutexLocker()
{
pthread_mutex_unlock(&mutex);
}
};
In which way is the above shown code exception safe? I don't see any exception handling over there.
Or does exception safe code mean where we can "add" the exception handling? So, the above shown code can be made exception safe by adding exception handling, but it isn't now?
Exception Safety is not about handling exceptions, it is about guaranteeing a number of properties about the program even in the presence of exceptions.
You can usually speak about the exception safety level of a given method:
No Guarantee: this method is exception unsafe, that is no guarantee is made, at all.
Basic Exception Guarantee: in case of exception no resource is leaked and the classes involved are still usable (but their state is unspecified), that is no memory leak, no file handle leak, no mutex leak and the invariants of the instances involved are still verified.
Strong Exception Guarantee: in case of exception, all state is reversed to what it was prior to beginning. This is a transaction like semantic.
NoThrow Guarantee: this method does not throw, it always succeeds.
In general, the NoThrow Guarantee only applies to the simplest methods (ie .size() on a vector for example) and the Strong Exception Guarantee may be costly to implement (being able to revert the effect or operating on a copy of the state may not be cheap).
On the other hand, the Basic Exception Guarantee is just that: Basic. Without it, safely operating a program is just impossible, so this is the least guarantee that is acceptable. If you leak resources or leave classes in an unusable state, the program may not be able to operate further.
This is why there is such an emphasis on RAII whenever exceptions are mentionned. Because RAII guarantees automatic cleanup of resources (memory, mutexes, files) whatever the path execution (regular return or exception) it is particularly desirable. However, RAII itself is not sufficient.
Related: Herb Sutter's GotW entry about Exception Safety and Exception Specifications.
the MutexLocker destructor is always called, also when an exception was raised in the block where it was constructed.
that is what makes a construct using your MutexLocker exception safe.
You don't have to handle an exception to be exception safe. You just have to survive when an exception is thrown.
The MutexLocker helps you do this by unlocking the mutex when you leave the scope. It doesn't matter if you leave by a return statement or because an exception is thrown.
"Exception safe" is a fairly overloaded term, but I would use it to describe sections of code which can have exceptions thrown through them and still maintain certain invariants (such as - nothing changes, no resources are leaked, all objects keep a valid state).
As an example, your void * printHello (void* threadId) function is correct (in that it always matches pthread_mutex_lock (&demoMutex) with pthread_mutex_unlock (&demoMutex)), but if someone changed the section in the middle so that it could throw an exception (for example, by setting the throw flags on std::cout), then your code would then permanently lock demoMutex, with no hope for it ever being released. This would constitute a bug in your program. void * printHello (void* threadId) is said to be "exception unsafe" because of this way in which bugs can easily be introduced into your program by adding exception handling to seemingly unrelated parts.
Using a RAII class to manage resources a good way to go about writing exception safe code (and is the resource management style to use in C++), because it avoids the need for duplicate manual cleanup in catch(...) blocks, and it enforces the cleanup of resources by using the type system.
A code which handles the exceptions well is called an exception safe code?
Yes, but you do not say what well is. This is a good read on exception safety.
In which way is the above shown code exception safe?
That code is not exception safe in itself. That is meant to be used in a exception safe code. For example :
void bar()
{
throw std::runtime_error( "lala" );
}
void foo()
{
pthread_mutex_lock(&mutex);
bar();
// OPS! mutex not unlocked
pthread_mutex_unlock(&mutex);
}
This problem is solved by using the class that automatically unlock the exception. Next example has exception handling with strong guarantees :
void foo()
{
MutexLocker locker( mutex );
try {
bar();
} catch ( const std::runtime_error & )
{
// revert changes
}
}
The code you provided serves the purpose well. Simply because when execution leaves the block in which the MutexLocker object is defined, the object is destroyed and the mutex is released as per its destructor. This holds no matter the reason for the exit.
You don't have to code this class yourself though. The C++ standard specifies a class named lock_guard that does exactly that.
http://en.cppreference.com/w/cpp/thread/lock_guard
I know that I shouldn't throw exceptions from a destructor.
If my destructor calls a function that can throw an exception, is it OK if I catch it in the destructor and don't throw it further? Or can it cause abort anyway and I shouldn't call such functions from a destructor at all?
Yes, that's legal. An exception must not escape from the destructor, but whatever happens inside the destructor, or in functions it calls, is up to you.
(Technically, an exception can escape from a destructor call as well. If that happens during stack unwinding because another exception was thrown, std::terminate is called. So it is well-defined by the standard, but it's a really bad idea.)
Yes.
Look at the std::fstream class in the standard library for an example.
close() could potentially throw an exception.
The destroctor can call close() but the destructor does not throw (it will swallow any exceptions).
The concept is that if the destructor calls any methods that can throw then these methods should be public. Thus if the user of your object wants to check for exceptions they can use the public methods and handle the exception. If they do not care about the exception then just let the destructor handle the problem.
Going back to the std::fstream example.
{
std::fstream text("Plop");
// Load Text.
// I don't care if the close fails.
// So let the destructor handle it and discard exceptions
}
{
// If this fails to write I should at least warn the user.
// So in this case I will explicitly try and close it.
try
{
std::ofstram password("/etc/password");
// Update the password file.
password.close();
}
catch(...)
{
Message.ShowDialog("You failed to update the Password File");
}
}
You can find some examples here: https://software.intel.com/sites/products/documentation/doclib/iss/2013/sa-ptr/sa-ptr_win_lin/GUID-D2983B74-74E9-4868-90E0-D65A80F8F69F.htm
If an exception leaves destructor during stack unwinding of another exception being propagated, then std::terminate() is called.
When no stack unwinding is in progress, an exception can leave destructor without std::terminate() getting called. However, for objects allocated on heap this will result in memory leak because "operator delete" will not be called for the object who throws exception out of its destructor. Surprisingly, the destructor of base class still gets called in this case: What happens to base class destructor if a derived class destructor throws an exception
If the exception is catched inside the destructor (so that the exception does not leave the destructor), then no problem even if stack unwinding of another exception is in progress. This case is described more deeply here: http://bin-login.name/ftp/pub/docs/programming_languages/cpp/cffective_cpp/MEC/MI11_FR.HTM
Simple answer, never allow an exception from a dtor!
The complicated answer. You only get really nailed if the exception escapes the dtor while another exception is active. The normal case for this is when you are already unwinding the stack from another exception and the object in question is destroyed. In that case if the exception escapes the dtor then std::terminate is called, note you can put in your own handler for std::terminate by calling std::set_terminate. The default implementation of std::terminate is to call abort.
To complicate things more, most functions that want to make any guarantee about their exception safety, mainly the basic guarantee or the strong guarantee, rely on the underlying types to themselves not throw in their dtor*
The real question is, what state would your program be in when this error occurs? How can you recover? Where should this recovery be handled? You need to look at your specific case and work these issues out. Sometimes it's just fine to catch the exception and ignore it. Other times you need to raise some red flags.
So the answer is: it allowed by C++ to throw an exception in a dtor, but you shouldn't ever allow it to escape.
*Here's a brief synopsis of the exception guarantees (here's a much longer article)
Recap: Briefly define the Abrahams exception safety guarantees (basic,
strong, and nothrow).
The basic guarantee is that failed
operations may alter program state,
but no leaks occur and affected
objects/modules are still destructible
and usable, in a consistent (but not
necessarily predictable) state.
The strong guarantee involves
transactional commit/rollback
semantics: failed operations guarantee
program state is unchanged with
respect to the objects operated upon.
This means no side effects that affect
the objects, including the validity or
contents of related helper objects
such as iterators pointing into
containers being manipulated.
The nothrow guarantee means that
failed operations will not happen. The
operation will not throw an exception.
You may find this page from C++ FAQ Lite to be informative. The basic answer is, "don't do it." Where exactly do you plan to catch this exception? Whatever you plan on doing when you catch that exception, just do it with a function call instead or something (e.g. log it or set a flag to warn the user or whatever). Throwing exceptions from the destructor runs the risk of causing your entire program to terminate.