Can a function marked as noexcept have exceptions inside? - c++

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]

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

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.

Using `throw;` on a modified exception

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.

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.

Exception thrown in handler functions

I am reading following text in applied C++ book.
Can exceptions be thrown from within our handler functions? The answer
is yes, an error can indeed be thrown. The problem is that this
exception must be in every exception specification that may be
tranversed until the exception is caught. If this is not done, the
application will call std::terminate(). For a large system, this
amounts to adding an exception specification to every function ,
unless you understand the dynamics of your application perfectly. It
is also important to cath all exceptions within your destructor;
otherwise, std::terminate() will be called as well in this case.
In above text I have following questions and need your help in understanding.
What does author mean by "exception must be in every expection specification that may be traversed" ?
My understanding is that destructor we cannot use exceptions. What does author mean to catch all exceptions within your destructor.
Request to clarify with simple examples
Thanks for your time and help.
Generally, exception specifications are a bad idea, because it produces a lot of refactoring and scale problems (The problems wich the autor talks about) when you modify the specifications. This is the case of java checked exceptions. C++ has no checked exceptions, but the problem with exception specifications are the same, if you want to write an uniform API.
In fact exception specifications are deprecated since C++11. C++11 uses noexcept specifier to ensure that a function not throws any exception. This allows certain compiler optimizations, and of course provides guaranties for the user of the function. If a function doesn't have the noexcept specifier, it can throw a exception or not.
Exceptions are, as it name says, exceptional. That is, using try...catch for flow-control is a bad programming technique. If your program is well designed, when a exception is thrown, means something go very very wrong. That is, a exceptional execution case. And normally that exceptional execution event translates to execution abort. This is why functions not have try..catch blocks everywhere where an exception could be thrown.
When an exception is thrown and not caught, the stack unwinds. This means that destructors will be called, everything will be cleaned up nicely. But consider this:
foo::~foo()
{
bar();
}
If we reach the destructor of foo because of an uncaught exception, and bar(); happens to throw, the application is immediately terminated, because C++ can not handle more than one exception at once.
This would not have happened if we, e.g. swallowed the exception:
foo::~foo()
{
try { bar(); } catch(...) { /* nom nom */ }
}
Update:
The first part refers to exception specifications like this:
struct foo
{
void bar() throw();
}
Valid syntax for this specification is
throw() // does not throw any exception
throw( list of exceptions ) // may throw one of these exceptions
throw(...) // may throw any exception
but as rodrigo mentioned, this turned out to be a bad idea, because these specifications led to dynamic checks (during runtime) whether an exception is thrown, significantly slowing down the performance.
In C++11 it is replaced by the noexcept keyword:
noexcept(true)
noexcept(false)
noexcept // identical to noexcept(true)
which is a guarantee that you give to the compiler, not the other way around.
But now finally to your question. When you give throw exception specification in some nested chain, and you throw an exception in a deeply nested function, you will have to update the signature of every function along the way. Another very good reason why exception specifications were stupid and should not be used anymore.
Exceptions specifications turned out to be a bad idea, and I think that they are deprecated in the latest revision of the language, so I'd just ignore it.
Generally speaking, destructors must not throw any exception. Because they are called during the stack unwinding that happens when an exception is thrown/catch. If an exception is thrown while the stack is unwinding, the program will abort. The easy/safe solution is to wrap the destructor body with a try {...} catch (..} {} block.