As a follow-up to my previous question:
If I change the code as follows:
struct ExceptionBase : virtual std::exception{};
struct SomeSpecificError : virtual ExceptionBase{};
struct SomeOtherError : virtual ExceptionBase{};
void MightThrow();
void HandleException();
void ReportError();
int main()
{
try
{
MightThrow();
}
catch( ... )
{
HandleException();
}
}
void MightThrow()
{
throw SomeSpecificError();
}
void HandleException()
{
try
{
throw;
}
catch( ExceptionBase const & )
{
// common error processing
}
try
{
throw;
}
catch( SomeSpecificError const & )
{
// specific error processing
}
catch( SomeOtherError const & )
{
// other error processing
}
try
{
ReportError();
}
catch( ... )
{
}
}
void ReportError()
{
throw SomeOtherError();
}
The "last handler" for the original exception (i.e. the one in main) has not exited when the second exception is thrown, so are both exceptions active? Is the original exception still available once we leave the handler for the second exception?
C++11 (N3242):
15.1p4: The memory for the exception object is allocated in an unspecified way, except as noted in 3.7.4.1. If a
handler exits by rethrowing, control is passed to another handler for the same exception. 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 (18.8.5) that refers to the exception object is
destroyed, whichever is later.
(std::exception_ptr is a C++11 feature, and isn't used in your example code.)
15.3p7: 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.
15.3p8: The exception with the most recently activated handler that is still active is called the currently handled exception.
15.1p8: A throw-expression with no operand rethrows the currently handled exception (15.3).
Or equivalently, I think, throw; always refers to the exception caught by the innermost catch block which is currently executing. Except that I haven't defined 'innermost' and 'executing' as carefully as the Standard defined all its terms above.
And yes, more than one exception object can be allocated at a time, and C++ is required to make sure they live long enough to do "the right thing" when you try to rethrow.
Not sure how standard it is, but if i add a throw; right before the end of HandleException and compile with g++, the resulting program tells me this:
root#xxxx [~/code]# ./a.out
terminate called after throwing an instance of 'SomeSpecificError'
what(): 17SomeSpecificError
Aborted
Note the exception type. That's the exception that was thrown in MightThrow, not the one from ReportError.
VS2010 reports a SomeSpecificError as well.
There is only one "active exception" at a time. When you throw another exception in an exception handler, in effect you are changing the type of the exception that is being propagated up the stack.
(As an aside, is all this necessary? Do you really find this code easy to read?)
[update]
As for the standard reference... ISO/IEC 14882:2003, section 15.3 [except.handle], paragraph 8 reads:
An exception is considered handled upon entry to a handler. [Note: the
stack will have been unwound at that point. ]
So another way to say this is, as soon as you enter the catch block, the original exception is no longer active.
Also, the uncaught_exception() function will return false as soon as the catch block is entered. Section 15.5.3 [except.uncaught] reads:
The function
bool uncaught_exception() throw()
returns true after completing evaluation of the object to be thrown until completing the
initialization of the exception-declaration in the matching handler
(18.6.4). This includes stack unwinding. If the exception is rethrown
(15.1), uncaught_exception() returns true from the point of rethrow
until the rethrown exception is caught again.
[update 2]
Also relevant is section 15.3 paragraph 4:
The memory for the temporary copy of the exception being thrown is
allocated in an unspecified way, except as noted in 3.7.3.1. The
temporary persists as long as there is a handler being executed for
that exception. In particular, if a handler exits by executing a
throw; statement, that passes control to another handler for the same
exception, so the temporary remains. When the last handler being
executed for the exception exits by any means other than throw; the
temporary object is destroyed and the implementation may deallocate
the memory for the temporary object; any such deallocation is done in
an unspecified way. The destruction occurs immediately after the
destruction of the object declared in the exception-declaration in the
handler.
So the original exception is destroyed as soon as the handler is exited via any means other than a naked throw;. So if you throw some other exception, that exits the handler and destroys the original exception.
Related
I have a portability question concerning the lifetime of exception. In the code below, an exception is thrown in one thread (mySlave) and transferred to another thread (myMaster) using a std::exception_ptr. myMaster is always waiting for different events via a std::condition_variable. An exception in mySlave is such an event. In the predicate function of the wait in myMaster, I check if the exception pointer is null. If an exception has been thrown in mySlave, I copy the exception pointer to a temporary variable in myMaster, set the original exception pointer to null and rethrow it in myMaster. This way, the original exception pointer is ready to serve in the predicate function once the program has recovered from the exception.
This works fine with VC14, but the final software is likely to be ported to other platforms in the future. In my code, all exception_ptr references to the exception will run out of scope after the rethrow, thus the original exception will be destroyed. My concern is if std::rethrow_exception is guaranteed to always generate a copy of the exception when rethrowing it, or if it could also use a reference to the exception, causing it to be no longer valid when I try to catch if in myMaster?
#include <mutex>
#include <thread>
#include <atomic>
#include <exception>
#include <iostream>
#include <memory>
class SomeClass
{
public:
/*...*/
void MaseterFunction();
void SlaveFunction();
private:
/*...*/
std::mutex mutex_gotEvent;
std::condition_variable condVar_gotEvent;
std::exception_ptr slaveLoopException;
/*...*/
std::atomic<bool> running = true;
};
class MyException : public std::runtime_error
{
public:
MyException() : std::runtime_error("Ooops") {}
};
void SomeClass::SlaveFunction()
{
try
{
throw MyException();
}catch(const std::exception& e)
{
std::unique_lock<std::mutex> lock(mutex_gotEvent);
slaveLoopException = std::current_exception();
condVar_gotEvent.notify_all();
}
}
void SomeClass::MaseterFunction()
{
while (running)
{
try
{
{
/*Wait for something interesting to happen*/
std::unique_lock<std::mutex> lock(mutex_gotEvent);
condVar_gotEvent.wait(lock, [=]()->bool {
return !(slaveLoopException == nullptr); // Real code waits for several events
});
}
/*Care for events*/
/*...*/
if (slaveLoopException)
{
std::exception_ptr temp_ptr = slaveLoopException;
slaveLoopException = nullptr;
std::rethrow_exception(temp_ptr);
}
}
catch (const MyException& e)
{
std::cout << e.what();
running = false;
}
}
}
int main()
{
std::shared_ptr<SomeClass> someClass = std::make_shared<SomeClass>();
std::thread myMaster([someClass]() {someClass->MaseterFunction(); });
std::thread mySlave([someClass]() {someClass->SlaveFunction(); });
std::cin.ignore();
if (myMaster.joinable())
{
myMaster.join();
}
if (mySlave.joinable())
{
mySlave.join();
}
return 0;
}
I thought about declaring temp_ptr at class level or use a std::atomic<bool> variable in addition to the exception pointer to be used in the predicate function. However both of these solutions would keep the exception alive after it is no longer used, which seem not very elegant to me. It would also be possible to set the exception pointer to null in each catch block in myMaster, but I think that this is likely to introduce bugs when new exceptions are added later on and the programmer forgets to null the exception pointer.
EDIT:
I found the following statements on this subject:
Statement 1:
The exception object referenced by an std::exception_ptr remains valid
as long as there remains at least one std::exception_ptr that is
referencing it
Statement 2:
The VS implementation of rethrow_exception appears to make a copy of
the exception. Clang and gcc do not make copies.
Statement 3
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 (§18.8.5)
that refers to the exception object is destroyed, whichever is later.
From (1) I would expect the exception to be destroyed too early. From (2) I would expect this to be of no effect when using VC as a copy is used anyway. From 3, I can't tell if this could save me when using gcc or clang. I mean, the exit takes place by rethrowing, but it is not rethrown from a handler. Is the new handler already considered active when the temporary pointer is destroyed or is the pointer destroyed first and with it the exception, leaving the follow up catch blocks with an invalid exception reference?
CppRef states that rethrow_exception -- Throws the previously captured exception object. I haven't checked the standard myself (but see below), but:
Speculation
It seems likely to me that from the point onwards where you rethrow the exception, exception handling is "back to normal", i.e. it is the job of the implementation to keep the thrown object around, and the language doesn't care whether you threw via a normal throwor via a rethrow_exception.
Stated differently: The exception_ptr needs to be valid at the point of rethrow_exception, after this, the thrown exception is the same as any other and whether or not it shares with the original exception pointer shouldn't matter.
OP provided a good link with a standard quote:
4/ The memory for the exception object is allocated in an unspecified way, except as noted in §3.7.4.1. If a handler exits by rethrowing, control is passed to another handler for the same exception. 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 (§18.8.5) 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. [ Note: a thrown exception does not propagate to other threads unless caught, stored, and rethrown using appropriate library functions; see §18.8.5 and §30.6. —end note ]
Which seems to imply what I wrote above: The exception object lives as long as necessary: the whichever is later part of the quote seems to explicitly call this out.
Update: I missed that OP doesn't re-throw from the handler, so I am also unsure what is supposed to happen here.
I do believe that after rethrow_exception the (new) exception in flight should be treated as-if it was generated by a normal throw expression - anything else makes little sense.
The way I speculate here is that even prior to std::exception_ptr every implementation had an internal mechanism that was similar to std::exception_ptr in that it had to keep the thrown exception object (copy or not) alive outside of normal stack frames until it was no longer needed by any handler up the stack. So I can speculate that clang or gcc would not do a copy, but instead hold an "internal exception_ptr" as soon as you invoke throw/rethrow_exception.
Under exceptional circumstances, I want my program to stop processing, output an error to std::cerr, clean up, and exit.
However, calling exit() will not call all the destructors of any objects that have been constructed. I would like to have the destructors called nicely, so I wrapped all the code in a try-catch block, something like this:
int main(int argc, char** argv){
try {
bool something_is_not_right = false;
/* lots of variables declared here */
/* some code that might set something_is_not_right to true goes here */
if(something_is_not_right){
std::cerr << "something is not right!!!" << std::endl;
throw '\0'; // dummy unused variable for throwing.
}
}
catch (...) {}
return 0;
}
In this way, I get guaranteed destruction of all my variables. But I can't seem to find a way to get C++ to throw nothing. throw; has a special meaning in C++; it isn't throwing nothing.
Is there a way to throw nothing?
No
It's not possible to throw nothing. You need to throw something. While you may have seen people use the throw keyword without anything, this just means they are re-throwing the currently handled exception.
This is not a direct answer to your question, but a personal recommendation.
You might want to take a look at the predefined exceptions of stdexcept which cover almost any exceptional behaviour that occurs in a program. In your case I would throw a std::runtime_error. Also, only catch what you expect to be thrown and not catch 'em all. If you really want to catch everything, then catch std::exception (the base class of all standard exceptions).
In my opinion handling unknown exceptions doesn't really make sense and the only logical consequence is to just abort execution.
#include <iostream>
#include <stdexcept>
int main()
{
try
{
bool something_is_not_right = true;
if ( something_is_not_right )
throw std::runtime_error("something is not right!!!");
}
catch (std::runtime_error& e)
{
std::cerr << e.what() << '\n';
throw;
}
}
How do you know that the reason for the catch is your error or something else (out of memory is always a good one). If you detect an error, then you should create and throw the reason for that error in a custom exception. Then in main, you can tell the difference between your detected error and something you didn't expect. It's just good practice.
Well you "can" but it doesn't throw nothing. It terminates.
5.17 Throwing an exception:
Evaluating a throw-expression with an operand throws an exception (15.1)
A throw-expression with no operand rethrows the currently handled exception (15.3).
If no exception is presently being handled, evaluating a throw-expression with no operand calls std::terminate()
This is valid:
int main () {
throw;
return 0;
}
Source used: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4296.pdf
But it won't cleanup anything. std::terminate is used when the cleanups fail.
Otherwise you have to use operand, and then this section becomes relevant:
15.1 Throwing an exception [except.throw]
Throwing an exception copy-initializes (8.5, 12.8) a temporary object, called the exception object. The temporary is an lvalue and is used to initialize the variable declared in the matching handler (15.3).
So you have to pass something that is able to be initialized, which by definition cannot be nothing.
In order to ensure full cleanup you have to throw an exception and catch it somewhere. Implementations are not required to clean up stack objects when an exception is thrown but not caught. The requirement (in [except.handle]/9) when an exception is thrown but not caught is that the program calls std::terminate(), and it's implementation-defined whether stack objects are cleaned up.
I am not sure if this is a issue with the compiler or if I am doing something wrong. I am using Visual Studio 2013 compiler.
I have a class where I need to acquire significant amount of resources in my constructor initializer list most of which can throw an exception. I wrapped up the member initializer list in a function try block and caught the exception there. But my program still aborts even though the catch clause doesn't re-throw the exception. I am not allowed to post the actual code. So I have reproduced the issue with this equivalent demo code. Can someone please help me address this?
#include <iostream>
using namespace std;
class A{
public:
A() try : i{ 0 }{ throw 5; }
catch (...){ cout << "Exception" << endl; }
private:
int i;
};
int main(){
A obj;
}
On executing this code I get a windows alert "abort() has been called". So I guess the system is treating this as an uncaught exception and calling terminate().
On the other hand if I wrap the construction of the object in main() in a try-catch block then the exception is caught properly and the program terminates normally.
Can someone please tell me if I am doing something wrong here?
There's a relevant gotw
http://gotw.ca/gotw/066.htm
Basically even if you don't throw in your catch block, the exception will automatically be rethrown
If the handler body contained the statement "throw;" then the catch
block would obviously rethrow whatever exception A::A() or B::B() had
emitted. 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.
This is normal behaviour according to the cppreference.com documentation for function-try blocks: a so-called function-try-block on a constructor or destructor must throw from its catch-clause or else there is an implicit rethrow after the catch-clause.
This makes perfect sense: the object A has not been properly constructed and hence is not in a state fit for use: it must throw an exception. You have to ensure whether the construction succeeded at the place where the object is constructed, i.e. in the case of your example in main().
Exception cannot be caught in constructor function-try-block.
n3376 15.2/15
The currently handled exception is rethrown if control reaches the end
of a handler of the function-try-block of a constructor or destructor.
You should catch it in object creation place.
I suggest you read the article: "GotW #66 Constructor Failures"on the site:http://gotw.ca/gotw/066.htm
I am not sure if this is a issue with the compiler or if I am doing something wrong. I am using Visual Studio 2013 compiler.
I have a class where I need to acquire significant amount of resources in my constructor initializer list most of which can throw an exception. I wrapped up the member initializer list in a function try block and caught the exception there. But my program still aborts even though the catch clause doesn't re-throw the exception. I am not allowed to post the actual code. So I have reproduced the issue with this equivalent demo code. Can someone please help me address this?
#include <iostream>
using namespace std;
class A{
public:
A() try : i{ 0 }{ throw 5; }
catch (...){ cout << "Exception" << endl; }
private:
int i;
};
int main(){
A obj;
}
On executing this code I get a windows alert "abort() has been called". So I guess the system is treating this as an uncaught exception and calling terminate().
On the other hand if I wrap the construction of the object in main() in a try-catch block then the exception is caught properly and the program terminates normally.
Can someone please tell me if I am doing something wrong here?
There's a relevant gotw
http://gotw.ca/gotw/066.htm
Basically even if you don't throw in your catch block, the exception will automatically be rethrown
If the handler body contained the statement "throw;" then the catch
block would obviously rethrow whatever exception A::A() or B::B() had
emitted. 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.
This is normal behaviour according to the cppreference.com documentation for function-try blocks: a so-called function-try-block on a constructor or destructor must throw from its catch-clause or else there is an implicit rethrow after the catch-clause.
This makes perfect sense: the object A has not been properly constructed and hence is not in a state fit for use: it must throw an exception. You have to ensure whether the construction succeeded at the place where the object is constructed, i.e. in the case of your example in main().
Exception cannot be caught in constructor function-try-block.
n3376 15.2/15
The currently handled exception is rethrown if control reaches the end
of a handler of the function-try-block of a constructor or destructor.
You should catch it in object creation place.
I suggest you read the article: "GotW #66 Constructor Failures"on the site:http://gotw.ca/gotw/066.htm
For some multithreaded code, I would like to capture all exceptions and pass a them to a single exception handling thread. Here's the message passing framework:
#include <exception>
struct message
{
virtual ~message() = default;
virtual void act() = 0;
};
struct exception_message : message
{
std::exception_ptr ep;
virtual void act()
{
std::rethrow_exception(ep);
}
// ...
};
Here's the use case:
try
{
// ...
}
catch (...)
{
exception_message em { std::current_exception(); }
handler_thread.post_message(em);
}
The handler thread goes through all its messages and calls act(), and it can install its own try/catch block to handle all the posted exceptions.
Now I was wondering what happens if I send copies this message to multiple receivers. In general, messages may have any number of recipients, and so I don't want to put arbitrary restrictions on exception propagation messages. The exception_ptr is documented as a "shared-ownership" smart pointer, and rethrow_exception "does not introduce a data race".
So my question: Is it legitimate to duplicate an active exception by storing it in an exception_ptr, copying the pointer, and calling rethrow_exception multiple times?
From my understanding of the Standard, it is legitimate. However I would note that the rethrow does not duplicate the exception, and therefore the shared exception object itself is submitted to data races should you modify it and access it from other threads meantime. If the exception is read-only (once thrown), then you should not have any issue.
Regarding storage duration:
15.1 Throwing an exception [except.throw]
4 The memory for the exception object is allocated in an unspecified way, except as noted in 3.7.4.1. If a handler exits by rethrowing, control is passed to another handler for the same exception. 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 (18.8.5) 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.
Regarding data races:
18.8.5 Exception propagation [propagation]
7 For purposes of determining the presence of a data race, operations on exception_ptr objects shall access and modify only the exception_ptr objects themselves and not the exceptions they refer to. Use of rethrow_exception on exception_ptr objects that refer to the same exception object shall not introduce a data race. [ Note: if rethrow_exception rethrows the same exception object (rather than a copy), concurrent access to that rethrown exception object may introduce a data race. Changes in the number of exception_ptr objects that refer to a particular exception do not introduce a data
race. —end note ]
Regarding rethrow:
[[noreturn]] void rethrow_exception(exception_ptr p);
9 Requires: p shall not be a null pointer.
10 Throws: the exception object to which p refers.