Using `throw;` on a modified exception - c++

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.

Related

Is it allowed to call std::current_exception() in lambda which is called in a catch clause?

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().

When is a exception object destroyed (and can it be controlled)?

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)

What throw statement throws if i do not tell what type of object is to be thrown in c++?

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.

Can a function marked as noexcept have exceptions inside?

Let's say that I have a function marked as noexcept but there's a line of code inside that can throw. That line of code will be in a try block and the exception will be caught. Does that cause anything?
void MyFunc() noexcept
{
try {
throw std::exception("...");
} catch (const std::exception & e) {
// I'll deal with it here...
}
}
Searching for an exception handler is done from the inside out, searching one level less deep whenever nothing is found to handle the exception.
15.3 Handling an exception [except.handle]
4 The handlers for a try block are tried in order of appearance. [...]
[...]
6 If no match is found among the handlers for a try block, the search for a matching handler continues in a dynamically surrounding try block of the same thread.
15.4 Exception specifications [except.spec]
9 Whenever an exception is thrown and the search for a handler (15.3) encounters the outermost block of a function with an exception-specification that does not allow the exception, then,
[... std::unexpected() or std::terminate() is called. ]
The only time noexcept(true) has a visible effect is if an exception is thrown from inside the function, and no matching handler is present. No special effect is specified for an an exception with a matching handler, so that must run the same as in a noexcept(false) function.
Yes, this is perfectly legal, as long as the exception doesn't leak out of the function.
An implementation shall not reject an expression merely because when executed it throws or might throw
an exception that the containing function does not allow.
[except.spec/11 in C++11]

Is rethrowing an exception from catch block which has an nested exception okay?

The idea is "try you(), if it fails try _do(), if it fails report the exception from the first try, i.e., you()".
void that_thing() {
try {
you();
} catch( ... ) {
bool error=false;
try {
_do();
} catch( ... ) {
error = true;
}
if( error ) throw;
}
}
Testing with Gcc it worked fine, I was wondering if it will work with any compiler. Just to be clearer, the weird behavior I was expecting was that the throw; would rethrow the inner exception.
Edit: This question is NOT about the inner most catch, it is about rethrowing the outer exception after catching the inner most. The question is if this kind of rethrowing is legally definitely was not approached on the question that are being pointed as similar.
The standard requires implementations to properly nest exceptions. To quote from the standard:
15.1 Throwing an exception [except.throw]
...
8 A throw-expression with no operand rethrows the currently handled exception (15.3).
15.3 Handling an exception [except.handle]
...
7 A handler is considered active when initialization is complete for the formal parameter (if any) of the catch clause. ... A handler is no longer considered active when the catch clause exits or when std::unexpected() exits after being entered due to a throw.
8 The exception with the most recently activated handler that is still active is called the currently handled exception.
When your code reaches the throw;, the inner exception handler is no longer active: the catch clause has exited. The outer exception handler is still active: it has not yet exited, and std::unexpected() has not been called. Therefore, implementations must support this usage, and re-throw the outer exception. A global "current exception" pointer that gets cleared after the inner handler exits would not match the requirements of the C++ standard.