Link https://en.cppreference.com/w/cpp/error/current_exception provides the following description of current_exception():
If called during exception handling (typically, in a catch clause), captures the current exception object and creates an std::exception_ptr that holds either a copy or a reference to that exception object (depending on the implementation).
...
If the implementation of this function requires copying the captured exception object and its copy constructor throws an exception, the returned pointer will hold a reference to the exception thrown. If the copy constructor of the thrown exception object also throws, the returned pointer may hold a reference to an instance of std::bad_exception to break the endless loop.
I am trying to find out if the implementation of current_exception() in GCC7 copies captured exception object, or just returns the reference to an already existing object. So far, I think that GCC implements the second case. I've tried to check it by executing the following code:
class my_copy_exception : public exception
{
public:
my_copy_exception () : exception () {}
my_copy_exception (const my_copy_exception& other) :
exception(other)
{
throw my_copy_exception();
}
const char* what () const throw() {return "my_copy_exception";}
};
int main()
{
try
{
throw my_copy_exception();
}
catch (const exception& e)
{
cout << e.what() << endl;
exception_ptr eptr = current_exception();
try
{
rethrow_exception(eptr);
}
catch(const std::exception& en)
{
cout << en.what() << endl;
exception_ptr eptrn = current_exception();
cout << (eptr == eptrn) << endl;
}
}
}
It produces the following output:
my_copy_exception
my_copy_exception
1
Whether it is possible to claim that there is no copying of the exception object? If not, how to make current_exception() throw bad_exception?
The good thing about open source software like GCC 7 is that, rather than attempt to reverse engineer what it probably is doing, you can simply go and look at the source code to see exactly what it is doing.
In the case of GCC 7.4, the implementation of std::current_exception() can be found in libstdc++, more specifically, in libsupc++/eh_ptr.cc line 177:
std::exception_ptr
std::current_exception() noexcept
{
__cxa_eh_globals *globals = __cxa_get_globals ();
__cxa_exception *header = globals->caughtExceptions;
if (!header)
return std::exception_ptr();
// Since foreign exceptions can't be counted, we can't return them.
if (!__is_gxx_exception_class (header->unwindHeader.exception_class))
return std::exception_ptr();
return std::exception_ptr(
__get_object_from_ambiguous_exception (header));
}
The fist couple of lines here just fetch the currently active exception. If there is no active exception or the active exception did not come from this C++ runtime, then it returns an empty exception_ptr (see here, here, here, here, here, here, and here for the details on how these checks operate). If there is an active exception that did come from the C++ runtime, it then gets itself a pointer to the active exception object and constructs an exception_ptr. The exception_ptr constructor it uses simply increments the reference counter of the exception object.
Thus, it would seem that libstdc++ exceptions are reference-counted and a copy is never made in the libstdc++ implementation of std::current_exception() for GCC 7, which is in accordance with the requirements of the specification and seems to match your observations…
Related
So lets say I have:
struct test {
bool a;
int b;
};
int main()
{
std::unique_ptr<test> ptr;
// don't init the ptr
try
{
if (!ptr->a)
{
std::cout << "ok" << std::endl;
}
}
catch (const std::exception &ex)
{
std::cout << "ex: " << ex.what() << std::endl;
}
return 1;
}
So here I setup a unique pointer, but I don't init it (to simulate this in a larger code base) but I want to catch the exception.
The problem is that my exception is not called - I just get a crash (memory access fault)
I read a few similar questions (but not quite the same) that suggested that I pass the exception by reference - but this did not work.
So is it possible to catch a unique_ptr de-reference exception?
EDIT: I should add that this is on Windows 7 box running MSVS2012 executable - incase it is relevant!
So is it possible to catch a unique_ptr de-reference exception?
There is no unique_ptr dereference exception to catch.
As the documentation says,
The behavior is undefined if get() == nullptr
You can easily write your own smart pointer with this Java-like behaviour, but it does mean paying for a test-and-branch on every dereference, which in general seems silly.
For the slightly different problem described in comments:
I have a list of unique_ptr's - I was trying to avoid individually checking each one by putting a try block around it.
the sane solution is probably to check it once and not on every subsequent dereference:
if(any_of(begin(ptrs), end(ptrs), logical_not<unique_ptr<test>>{})
{
throw MyNullPointerException();
}
Per subsequent comments, you could just add a check-and-throw wrapper to your constructing function.
In C++17 you can almost get what you want by instead returning an optional<unique_ptr<test>> (ie, it either contains a populated unique_ptr, or nothing at all: in that case, calling value to extract the unique_ptr would throw std::bad_optional_access if there isn't really one there).
If you can import ot (or don't have C++17), the GSL is probably even better with gsl::not_null<T>. For example, you could instead store these things in your container
using unique_not_null = std::unique_ptr<gsl::not_null<test>>;
The main problem with throwing exceptions from destructor is that in the moment when destructor is called another exception may be "in flight" (std::uncaught_exception() == true) and so it is not obvious what to do in that case. "Overwriting" the old exception with the new one would be the one of the possible ways to handle this situation. But it was decided that std::terminate (or another std::terminate_handler) must be called in such cases.
C++11 introduced nested exceptions feature via std::nested_exception class. This feature could be used to solve the problem described above. The old (uncaught) exception could be just nested into the new exception (or vice versa?) and then that nested exception could be thrown. But this idea was not used. std::terminate is still called in such situation in C++11 and C++14.
So the questions. Was the idea with nested exceptions considered? Are there any problems with it? Isn't the situation going to be changed in the C++17?
There is one use for std::nested exception, and only one use (as far as I have been able to discover).
Having said that, it's fantastic, I use nested exceptions in all my programs and as a result the time spent hunting obscure bugs is almost zero.
This is because nesting exceptions allow you to easily build a fully-annotated call stack which is generated at the point of the error, without any runtime overhead, no need for copious logging during a re-run (which will change the timing anyway), and without polluting program logic with error handling.
for example:
#include <iostream>
#include <exception>
#include <stdexcept>
#include <sstream>
#include <string>
// this function will re-throw the current exception, nested inside a
// new one. If the std::current_exception is derived from logic_error,
// this function will throw a logic_error. Otherwise it will throw a
// runtime_error
// The message of the exception will be composed of the arguments
// context and the variadic arguments args... which may be empty.
// The current exception will be nested inside the new one
// #pre context and args... must support ostream operator <<
template<class Context, class...Args>
void rethrow(Context&& context, Args&&... args)
{
// build an error message
std::ostringstream ss;
ss << context;
auto sep = " : ";
using expand = int[];
void (expand{ 0, ((ss << sep << args), sep = ", ", 0)... });
// figure out what kind of exception is active
try {
std::rethrow_exception(std::current_exception());
}
catch(const std::invalid_argument& e) {
std::throw_with_nested(std::invalid_argument(ss.str()));
}
catch(const std::logic_error& e) {
std::throw_with_nested(std::logic_error(ss.str()));
}
// etc - default to a runtime_error
catch(...) {
std::throw_with_nested(std::runtime_error(ss.str()));
}
}
// unwrap nested exceptions, printing each nested exception to
// std::cerr
void print_exception (const std::exception& e, std::size_t depth = 0) {
std::cerr << "exception: " << std::string(depth, ' ') << e.what() << '\n';
try {
std::rethrow_if_nested(e);
} catch (const std::exception& nested) {
print_exception(nested, depth + 1);
}
}
void really_inner(std::size_t s)
try // function try block
{
if (s > 6) {
throw std::invalid_argument("too long");
}
}
catch(...) {
rethrow(__func__); // rethrow the current exception nested inside a diagnostic
}
void inner(const std::string& s)
try
{
really_inner(s.size());
}
catch(...) {
rethrow(__func__, s); // rethrow the current exception nested inside a diagnostic
}
void outer(const std::string& s)
try
{
auto cpy = s;
cpy.append(s.begin(), s.end());
inner(cpy);
}
catch(...)
{
rethrow(__func__, s); // rethrow the current exception nested inside a diagnostic
}
int main()
{
try {
// program...
outer("xyz");
outer("abcd");
}
catch(std::exception& e)
{
// ... why did my program fail really?
print_exception(e);
}
return 0;
}
expected output:
exception: outer : abcd
exception: inner : abcdabcd
exception: really_inner
exception: too long
Explanation of the expander line for #Xenial:
void (expand{ 0, ((ss << sep << args), sep = ", ", 0)... });
args is a parameter pack. It represents 0 or more arguments (the zero is important).
What we're looking to do is to get the compiler to expand the argument pack for us while writing useful code around it.
Let's take it from outside in:
void(...) - means evaluate something and throw away the result - but do evaluate it.
expand{ ... };
Remembering that expand is a typedef for int[], this means let's evaluate an integer array.
0, (...)...;
means the first integer is zero - remember that in c++ it's illegal to define a zero-length array. What if args... represents 0 parameters? This 0 ensures that the array has at lease one integer in it.
(ss << sep << args), sep = ", ", 0);
uses the comma operator to evaluate a sequence of expressions in order, taking the result of the last one. The expressions are:
s << sep << args - print the separator followed by the current argument to the stream
sep = ", " - then make the separator point to a comma + space
0 - result in the value 0. This is the value that goes in the array.
(xxx params yyy)... - means do this once for each parameter in the parameter pack params
Therefore:
void (expand{ 0, ((ss << sep << args), sep = ", ", 0)... });
means "for every parameter in params, print it to ss after printing the separator. Then update the separator (so that we have a different separator for the first one). Do all this as part of initialising an imaginary array which we will then throw away.
The problem you cite happens when your destructor is being executed as part of the stack unwinding process (when your object was not created as part of stack unwinding)1, and your destructor needs to emit an exception.
So how does that work? You have two exceptions in play. Exception X is the one that's causing the stack to unwind. Exception Y is the one that the destructor wants to throw. nested_exception can only hold one of them.
So maybe you have exception Y contain a nested_exception (or maybe just an exception_ptr). So... how do you deal with that at the catch site?
If you catch Y, and it happens to have some embedded X, how do you get it? Remember: exception_ptr is type-erased; aside from passing it around, the only thing you can do with it is rethrow it. So should people be doing this:
catch(Y &e)
{
if(e.has_nested())
{
try
{
e.rethrow_nested();
}
catch(X &e2)
{
}
}
}
I don't see a lot of people doing that. Especially since there would be an exceedingly large number of possible X-es.
1: Please do not use std::uncaught_exception() == true to detect this case. It is extremely flawed.
Nested exceptions just add most-likely-ignored information about what happened, which is this:
An exception X has been thrown, the stack is being unwound, i.e. destructors of local objects are being called with that exception “in flight”, and the destructor of one of those objects in turn throws an exception Y.
Ordinarily this means that cleanup failed.
And then this is not a failure that can be remedied by reporting it upwards and letting higher level code decide to e.g. use some alternative means to achieve its goal, because the object that held the information necessary to do the clean up has been destroyed, along with its information, but without doing its cleanup. So it's much like an assertion failing. The process state can be very ungood, breaking the assumptions of the code.
Destructors that throw can in principle be useful, e.g. as the idea Andrei once aired about indicating a failed transaction on exit from a block scope. That is, in normal code execution a local object that hasn't been informed of transaction success can throw from its destructor. This only becomes a problem when it clashes with C++'s rule for exception during stack unwinding, where it requires detection of whether the exception can be thrown, which appears to be impossible. Anyway then the destructor is being used just for its automatic call, not in its cleanup rôle. And so one can conclude that the current C++ rules assume the cleanup rôle for destructors.
The real problem is that throwing from destructors is a logical fallacy. It's like defining operator+() to perform multiplication.
Destructors should not be used as hooks for running arbitrary code. Their purpose is to deterministically release resources. By definition, that must not fail. Anything else breaks the assumptions needed to write generic code.
The problem that may happen during stack unwinding with chaining exceptions from destructors is that the nested exception chain may be too long. For example, you have std::vector of 1 000 000 elements each of which throws an exception in its destructor. Let's assume the destructor of std::vector collects all exceptions from destructors of its elements into single chain of nested exceptions. Then resulting exception may be even bigger than original std::vector container. This may cause performance problems and even throwing std::bad_alloc during stack unwinding (that even couldn't be nested because there is not enough memory for doing that) or throwing std::bad_alloc in other unrelated places in the program.
I've got a few questions about throwing exceptions in C++.
From what I know about them...
An exception can be thrown from within the main() function. Any block of code that can throw an exception in the main() function should be surrounded by try and catch statements as follows
void foo(//args) {
if (...) {
throw "Error reached";
} ...
int main() {
...
try {
//Code that can throw an excpetion
} catch(const char* msg) (
cerr << msg << endl;
}
...
}
In the example above, why is the argument to the catch a const char *. Doesn't C++ allow for strings? Also, is it possible to throw an exception that isn't a const char *, like an int? or a char?
Does throwing an exception in foo, terminate the foo function?
Are there cases where you could put the try and catch statements in the same function as the throw?
Sorry if these are basic questions.
Thanks SO
why is the argument to the catch a const char *
Because you threw string literal which decays to const char*. In short, you catch what you throw.
Doesn't C++ allow for strings?
It does, but to catch string, you need to throw string in first place.
is it possible to throw an exception that isn't a const char *,
You can throw literally anything. It is a good idea to throw special exception classes, like std::exception and derived from it.
Does throwing an exception in foo, terminate the foo function?
Yes, it does.
Are there cases where you could put the try and catch statements in the same function as the throw?
If you want, you can do that. There are not much cases where doing it is a good idea.
It looks like you need to get a good book and read chapter about exceptions. In the meantime this super-FAQ entry might help you/
You can throw an object of any type.
EDIT: (Hopefully I got this right now)
What you have done is throw a C-string, which is of type const char[13] in this case. C-Arrays will decay to pointers to their first element, in this case a pointer of type const char*.
Typically what you want to do is throw a predefined exception object. They can be found in header <stdexcept> and are derived from a base class std::exception. The derived exception classes are for instance std::logic_error, std::range_error, std::bad_alloc etc.
Their constructors take a string as argument, so you can for instance
throw std::logic_error{"Negative values not allowed."};
This message can be accessed in a catch statement like this:
catch(std::exception &e) // capture reference to base class
{
std::cout << e.what() << '\n'; // what() of derived is called, since virtual
}
If an exception is caught, so-called stack unwinding takes place. You can then deal with the error locally, or rethrow the exception. Only when an exception is thrown and never caught, std::terminate() is called an the program aborted.
You can put try/catch statements anywhere. However, remember what the term "exception" actually means. Cases that can easily dealt with using a simple conditional expression if (n < 0) break; or something like that, don't need the exception treatment. Especially if you can realistically expect this kind of unwanted condition to be true often. Then it is not something "exceptional".
If you decide to deal with an error using exceptions and they can not be treated locally, you may put try/catch clauses around the beginning and end of main().
Since you can put several catch statements directly after a try statement, you can then begin to deal with more specific errors, or simply catch anything via catch(...) { //... }.
This is all described in great detail (including pointers on when and when not to use it, in the C++ FAQ.
EDIT: Here's an example that makes use of try/catch statements. However, not an exception object is caught, but an int (errno). Just to show, that you can really throw/catch anything you like. Let process_several_files() be a function somewhere nested in your code:
std::vector<std::string> process_several_files(std::vector<std::string> const& files)
{
std::vector<std::string> contents{};
contents.reserve(files.size()); // files contains file names from user input
for (auto const& file : files)
{
try
{
contents.emplace_back(get_file_contents(file.c_str())); // A "C like" function. get_file_contents() will throw "errno", if a file does not exist
}
catch(int err)
{
std::cerr << "***Error while opening " << file << " : " << std::strerror(err) << "***\n";
continue; // "scope" didn't change, just keep iterating!
}
}
return contents;
}
Is the following code safely throwing an exception with custom message?
#include <exception>
#include <sstream>
#include <string>
#include <iostream>
int main() {
try {
std::ostringstream msg;
msg << "give me " << 5;
throw std::exception(msg.str().c_str());
} catch (std::exception& e) {
std::cout << "exception: " << e.what();
}
}
With VC++-2008 this gives:
exception: give me 5
But now I wonder why the message "give me 5" from the local object msg is still available in the catch-block? By the time the message is printed both the stream- and the temporary string-object should have been deleted? Btw: This way of generating a message for an exception seems also to work accross several functions and also if new memory is allocated in the catch-block before printing the exception.
Or is it necessary to define a custom exception class with a std::string member in order to safely keep the message until printing it.
It's perfectly safe. The constructor that takes a C string as a single parameter makes a copy of the string. The constructor that takes a C string and a length parameter allow you to specify no memory be allocated and stores a pointer to the string (the length parameter is ignored).
Note that these two constructors are extensions to the std::exception class and are not standard. Also be aware that the constructor that takes a C string as a single parameter is not marked as explicit.
It's OK.
Per §15.1/3:
Throwing an exception copy-initializes (8.5, 12.8) a temporary object,
called the exception object.
and §15.1/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...
so after throw expression:
the expression will be copied (new object will be created by copy constructor) and you shouldn't worry about the local object.
About the msg and const char* which you're worrying... here is Microsoft's implementation:
exception::exception(const char * const & _What)
: _Mywhat(NULL), _Mydofree(false)
{
_Copy_str(_What);
//^^^^^^^^^^^^^^^^^
}
void exception::_Copy_str(const char * _What)
{
if (_What != NULL)
{
const size_t _Buf_size = strlen(_What) + 1;
_Mywhat = static_cast<char *>(malloc(_Buf_size));
if (_Mywhat != NULL)
{
_CRT_SECURE_STRCPY(const_cast<char *>(_Mywhat), _Buf_size, _What);
//^^^^^^^^^^^^^^^^^^
_Mydofree = true;
}
}
}
It copies the _What not just storing the pointer.
No, it's not safe, because std::exception doesn't have a constructor taking a char* in the standard. You are using an MS extension. To make it portable and safe, use std::runtime_error instead, to which you can pass a std::string in the ctor.
Is there any problem with throwing an object constructed on the stack in a try-block by non-const reference, catching it and modifying it, then throwing it by reference to another catch block?
Below is a short example of what I'm refering to.
struct EC {
EC(string msg) { what = msg; }
string where;
string what;
void app(string& t) { where += t; }
string get() { return what; }
};
try {
try {
try {
EC error("Test");
throw error;
}
catch (EC& e) {
e.app("1");
throw e;
}
}
catch (EC& e) {
e.app("2");
throw e;
}
}
catch (EC& e) {
e.app("3");
cout << e.where << endl;
cout << e.get() << endl;
}
Is it possible that this could cause e.what to contain junk, but e.where to remain intact? For example:
e.where is "123"
e.get() returns a lot of garbage data, until it happens to hit a null byte.
There's no such thing as "throwing by reference". It is simply impossible. There's no syntax for that. Every time you try to "throw a reference", a copy of the referenced object is actually thrown. Needless to say, there are no attempts to throw by reference in your code.
It is possible to catch a previously thrown exception by reference (even by a non-const one) and modify the temporary exception object through it. It will work. In fact, you can re-throw the now-modified existing exception object instead of creating a new one. I.e. you can just do
throw;
instead of
throw e;
in your catch clauses and still get the correctly behaving code, i.e. the original object (with modifications) will continue its flight throgh the handler hierarchy.
However, your code is ill-formed at the
e.app("1");
call (and other calls to app) since the parameter is non-const reference. Change the app declaration to either
void app(const string& t) { where += t; } // <- either this
void app(string t) { where += t; } // <- or this
for it to compile.
Otherwise, you code should work fine. You are not supposed to get any garbage from get(). If you do, it must be either a problem with your compiler or with your code that you don't show.