Consider the following code:
#include <iostream>
#include <stdexcept>
void foo()
{
throw std::runtime_error("How long do I live?");
}
int main()
{
try
{
foo();
}
catch (std::runtime_error& e)
{
std::cout << e.what() << std::endl;
}
}
Why can I catch the exception by reference, isn't std::runtime_error("How long do I live?") an rvalue?
How come the exception object is still alive in the catch block?
Where exactly are thrown exception objects stored? What is their lifetime?
In the C++ standard, paragraph 15.1.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.
Note that, in C++-standard talk, a handler denote a catch block with the correct argument type.
A thrown exception is not a temporary - the compiler-generated exception code keeps a permanent copy of it. So you can bind it to a non-const reference.
[edit]
I just check the standard and it actually refers to a temporary copy. However, the lifetime of the temporary is guaranteed to be at least as long as that of the exception handler.
As Neil said, there is internal compiler magic going on. Also, be aware that the compiler is allowed to create any number of copies of the exception object.
Kudos for trying to understand the details of the language. At the same time, IMHO, it is far more important to understand why you should catch an exception by reference (and throw it by value), than why you can.
People typically use a hierarchy of exception classes, and catching by reference allows you to leverage polymorphism, and catch an exception of the base class, when there is no need to handle individual exception types separately. If you couldn't catch by reference, you would have had to write a catch clause for every possible type of exception that can be thrown in the try clause.
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.
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
Is it safe to use unique_ptr?
When I use cout in destructor, sometimes it called more then one time. - so it make copy time-to-time. if it take two copy from one object - data can be lost..
#include <memory>
class MyException
{
std::unique_ptr<Type> data;
MyException();
~MyException() {cout<<"test"<<endl;}
MyException(MyException ex&);
};
int main()
{
try
{
try
{
throw MyException();
}
catch (const MyException& ex)
{
throw;
//or?
throw ex; //will be copied?
}
return 0;
}
catch(const MyException/*& will be missed. will ex be copied?*/ ex)
{
throw; //wich ex will be re-throw, copy or original?
//or?
throw ex; //will be copied?
}
}
Can I be sure, that data will not be lost between re-throws?
And is this good practic to use ptr inside exception to collect error info from different levels?
Also, can MyException.data be lost after:
std::exception_ptr ex = std::current_exception();
std::rethrow_exception(ex);
As you discovered, you should always say throw; when you want to re-throw an exception, not not throw ex;. Indeed, throw ex; will copy (and slice, if ex is a reference to a base class!).
So, always catch by reference, and always re-throw without naming the exception.
With gcc 4.7.3 your example doesn't compile, complaining about a missing copy constructor for MyException. This is in the line where it's first thrown, so throw MyException() itself already wants to make a copy (at least in gcc). See also this stackoverflow question and the C++ FAQ.
To answer your question about whether using pointers in exceptions is good practice, I would generally say no. Unless the data to be piggybacked onto the exception is huge (which would likely be a design problem), a stack allocated data structure should be preferred. Performance shouldn't be the main concern during exception handling anyway, so copying stuff around isn't a real problem.
If you really need a pointer (maybe Type has no copy constructor and you can't change that), using shared_ptr could help you in a pinch, although I feel like that would be an ugly hack. I would probably try and reduce the information passed via the exception to the bare minimum that would help callers identify and handle the problem.
Edit: I found the relevant section in the C++ standard, section 15.1, paragraph 5:
When the thrown object is a class object, the copy/move constructor and the destructor shall be accessible, even if the copy/move operation is elided.
So it's actually not legal C++ to throw an exception object without a copy constructor.
Say I've written some function myFunc that can throw const char* exceptions:
void myFunc()
{
int returnCode = whatever();
if (!returnCode)
{
std::string msg;
msg.append("whatever function failed");
std::cerr << msg << std::endl; // print warning message
throw msg.c_str(); // throw warning message as exception
}
}
And later I'm using it like so:
void myProgram()
{
try
{
myFunc();
}
catch(const char* str)
{
// is 'str' string memory valid here?
}
}
I realize this isn't really a good strategy for exception usage: better to throw and catch exception classes, not strings. But I'm curious about the scoping involved here.
msg.str() returns a temporary std::string. As temporaries are deleted at the end of a statement ;, the contents of the character string returned by c_str() become undefined when the throw ... ; statement terminates by leaving the scope via the exception mechanism.
(The lifetime of the const char* temporary is obviously extended to reach to the catch handler, but that does not help since the underlying buffer is gone).
Throwing std::string (i.e. throw msg.str();) would work, the lifetime of the temporary would be extended as intended.
Indeed the c_str() call is acting on a temporary (string) object and the pointer will be invalid when you catch it.
Not only that, but since the stringstream and stringcould do allocation, you need to make sure that you're not throwing because of heap problems. If you're at that point due to being out of memory you may bomb out even worse trying to create your exception. You generally want to avoid heap allocation during exceptional cases.
Are you unable to use say runtime_error or create your own exception type?
Note that if you had said:
throw "error";
you would be OK because the lifetime of the string literal is the lifetime of the program. But don't do it, anyway!
Something Alexander Gessler did not mention in his answer, is the possibility of an exception being thrown by by std::string itself during the creation of the temporary string object.
std::exception is guaranteed not to throw an exception during construction, std::string has no such guarantee.
An alternative approach (for classes) is to declare a private std::string object in your class. Assemble the error message prior to the throw, and then throw the c_str(). This will throw a const char* exception, the error message being valid until the next exception is thrown from that class (which would presumably modify the error string again.)
A simple example can be found here: http://ideone.com/d9HhX
Although this was answered over ten years ago, I would give some supplement:
https://learn.microsoft.com/en-us/cpp/cpp/exceptions-and-stack-unwinding-in-cpp
In the C++ exception mechanism, control moves from the throw statement to the first catch statement that can handle the thrown type. When the catch statement is reached, all of the automatic variables that are in scope between the throw and catch statements are destroyed in a process that is known as stack unwinding.
That's to say, any variables in the stack, including object variable, or basic type(int, char, etc) will be destroyed.
When throw an object in c++, c++ will actually make a cloned object by invoking the object copy constructor, the cloned object lifetime will valid through throw-catch.
reference:
C++: Throwing an exception invokes the copy constructor?
Now, return to the OP question, so, "throw msg.c_str();" is invalid because the msg object
is deleted (it's a auto variable), it happens to work because the memory is still there but actually freed.
So, just as #AlexanderGessler, #MarkB suggested,
the best c++ practice is: always throw string object, runtime_error, instead of throwing string.c_str()