What happens to exceptions thrown from functions launched via std::async?
#include <future>
#include <iostream>
#include <stdexcept>
void foo()
{
std::cout << "foo()" << std::endl;
throw std::runtime_error("Error");
}
int main()
{
try
{
std::cout << "1" << std::endl;
auto f = std::async(std::launch::async, foo);
f.get();
std::cout << "2" << std::endl;
}
catch (const std::exception& ex)
{
std::cerr << ex.what() << std::endl;
}
}
MSVC gives me the following output:
1
foo()
Error
Is it right that such exceptions will be caught outside the function by calling the get function?
From cppreference:
[...] if the function f returns a value or throws an exception, it is stored in the shared state accessible through the std::future that async returns to the caller.
And in the reference about std::future::get():
If an exception was stored in the shared state referenced by the future (e.g. via a call to std::promise::set_exception()) then that exception will be thrown.
So yes, if your function throws an exception, that exception is basically deferred into the future and rethrown on get().
Related
In the following snippet
#include <iostream>
#include <future>
int main()
{
auto ep = std::make_exception_ptr( X ); // (1)
std::promise<int> p;
p.set_exception(ep);
try {
p.get_future().get(); // (2)
} catch(const std::exception& exc) {
std::cout << exc.what();
}
return 0;
}
if X in line (1) is a type not extending std::exception, the call at line (2) will call terminate. I can't find anywhere this specification.
Godbolt with latest gcc and msvc
As noted in comments, the problem is not catching the right type of exception, e.g. using catch(...).
#include <iostream>
#include <sstream>
using std::string;
using std::cout;
using std::endl;
using std::ostringstream;
class illegalParameterValue {
private:
string message;
public:
illegalParameterValue() : message("Illegal parameter value") {}
explicit illegalParameterValue(const char* theMessage) {message = theMessage;}
void outputMessage() {cout << message << endl;}
};
int main() {
ostringstream s;
s << "index = " << 1 << " size = " << 2;
throw illegalParameterValue(s.str().c_str());
return 0;
}
I just use some code like this, but the throw will remind some warnings which called
Clang-Tidy: Throwing an exception whose type 'illegalParameterValue' is not derived from 'std::exception'
How can I solve this problem?
consider the following code:
try {
// do something that might throw an exception
}
catch (const std::exception &ex) {
// handle the exception
}
If you derive your illegalParameterValue class from std::exception, then the catch clause above will catch it (along with other kinds of exceptions derived from std::exception). As currently written, it will not. Your users will have to add another catch clause:
try {
// do something that might throw an exception
}
catch (const std::exception &ex) {
// handle std exceptions
}
catch (const illegalParameterValue &ip) {
// handle illegal parameter exeception
}
Maybe that's what you want, maybe not.
But there's a lot of code out there like the first case.
I am trying to design a killable_thread class which derives from std::thread. This is subsequent to my previous post on this subject and is version 2.
Here's the source code for the killable_thread class (v2):
#include <thread> /// thread
#include <exception> /// exception_ptr
#include <iostream> /// cout, endl
template<typename Tsk,
typename... Args>
class killable_thread : public std::thread
{
private:
std::exception_ptr& pex;
public:
/// inherit the thread class' constructor
/// [CPL], $20.3.5.1
using std::thread::thread;
using std::thread::operator=;
killable_thread(std::exception_ptr& pe,
Tsk tsk,
Args... args) :
thread {tsk, args...},
pex {pe}
{
}
void die()
{
try
{
std::cout << "diag: dying..." << std::endl;
throw std::runtime_error
{"thread instructed to die."};
}
catch (std::exception& e)
{
/** Set the exception_ptr to point to
this exception, so that it may be
propagated out of this thread. **/
pex = std::current_exception();
}
}
};
The tester is at the same link as above:
/// Tester ...
/// declarations ...
void test1();
void f();
std::exception_ptr pex {};
int main()
{
test1();
}
void test1()
{
try
{
killable_thread<decltype(f)> kt {pex, f};
kt.die();
if (pex)
std::rethrow_exception(pex);
std::cout << "thread didn't die."
<< std::endl;
}
catch (std::exception& e)
{
std::cout << "exception: " << e.what()
<< std::endl;
}
}
void f()
{
}
I get the following runtime error:
diag: dying...
terminate called without an active exception
bash: line 7: 22929 Aborted (core dumped) ./a.out
That is, though I handle the exception and set the exception_ptr within the die() member, the tester aborts because I don't join() with the thread.
When I do join() with the thread however in this version of the tester, the runtime error disappears (naturally):
void test1()
{
try
{
killable_thread<decltype(f)> kt {pex, f};
kt.die();
kt.join();
if (pex)
std::rethrow_exception(pex);
std::cout << "thread didn't die."
<< std::endl;
}
catch (std::exception& e)
{
std::cout << "exception: " << e.what()
<< std::endl;
}
}
The message in this case is:
diag: dying...
exception: thread instructed to die.
In fact, this is what I want killable_thread to do, without join()ing in the tester.
How can I get this to work?
The following code makes it so that a destructor is called twice.
#include <iostream>
#include <memory>
#include <exception>
#include <cstdlib>
void myterminate()
{
std::cout << "terminate\n";
abort();
}
class data
{
int a;
public:
data(int a) : a(a) { std::cout << "ctor " << a << "\n"; }
~data() { std::cout << "dtor " << a << "\n"; }
static data failure(int a) { return data(a); }
};
void main()
{
std::set_terminate(myterminate); //terminate is not called
try
{
std::unique_ptr<data> u;
u.reset(&data::failure(1));
std::cout << "no worries\n"; //this prints
//destructor called at try-block end and attempt to destruct an invalid memory block.
}
catch (...)
{
std::cout << "caught\n"; //this can not catch the error
}
std::cout << "end\n"; //program crash, will not be called
}
How would I catch an error like this in production?
On a Release build the program crashes. On a Debug build it the on my system is:
How would I catch an error like this in production?
You cannot. The standard says that invalid memory access has undefined behaviour. There is no standard way to "catch" UB. Catching and terminate handler are for exceptions, which are defined behaviour.
What you could do, is use the debug build in production, and run it with valgrind or similar tool, so that you can at least analyze the error.
"try/catch" such mistakes will not catch, because in this case a great probability of a crash. But a moment of destruction you can try to catch, using signals and more menne dignified exit the program.
Looking away: #include , signal(), sig_atomic_t ...
First as noted in the comments you declare main as void main where the standard only allows two forms in § 3.6.1
An implementation shall not predefine the main function. This function
shall not be overloaded. It shall have a declared return type of type
int, but otherwise its type is implementation-defined. An
implementation shall allow both
(2.1) — a function of () returning int and
(2.2) — a function of (int, pointer to pointer to char) returning int
Secondly you are resetting your unique_ptr to manage a temporary which when unique_ptr gets destroyed at the end of its scope will be deleted which results in undefined behavior. You can't predict/catch errors resulting from undefined behavior.
What you should do (if you really want to use dynamically allocated memory) you can return a pointer to object on the heap:
#include <iostream>
#include <memory>
#include <exception>
#include <cstdlib>
void myterminate()
{
std::cout << "terminate\n";
abort();
}
class data
{
int a;
public:
data(int a) : a(a) { std::cout << "ctor " << a << "\n"; }
~data() { std::cout << "dtor " << a << "\n"; }
static data* failure(int a) { return new data(a); }
};
int main()
{
std::set_terminate(myterminate); //terminate is not called
try
{
std::unique_ptr<data> u;
u.reset(data::failure(1));
std::cout << "no worries\n"; //this prints
//destructor called at try-block end and attempt to destruct an invalid memory block.
}
catch (...)
{
std::cout << "caught\n"; //this can not catch the error
}
std::cout << "end\n"; //program crash, will not be called
}
Online code: http://melpon.org/wandbox/permlink/pdiijgDxBshVOYRu
I have following program:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class MyError : public runtime_error
{
public:
MyError(string mess = "");
~MyError(void);
};
MyError::MyError(string mess) : runtime_error(mess)
{
cout << "MyError::MyError()\n";
}
MyError::~MyError(void)
{
cout << "MyError::~MyError\n";
}
int main(void)
{
try {
throw MyError("hi");
}
catch (MyError& exc) {
cout << exc.what() << endl;
}
cout << "goodbye\n";
return 0;
}
Which prints the following:
MyError::MyError()
MyError::~MyError
hi
MyError::~MyError
goodbye
Why is the destructor of the exception (~MyError()) called twice?
I assumed that throw creates a new object, but I do not understand why the class destructor is called.
If you instrument the exception's copy or move constructor, you'll find it's called once before the handler. There's a temporary exception object into which the thrown expression is copied/moved, and it is this exception object to which the reference in the handler will bind. C++14 15.1/3+
So the execution resulting from your code looks something like this (pseudo-C++):
// throw MyError("hi"); expands to:
auto tmp1 = MyError("hi");
auto exceptionObject = std::move(tmp1);
tmp1.~MyError();
goto catch;
// catch expands to:
MyError& exc = exceptionObject;
cout << exc.what() << endl;
// } of catch handler expands to:
exceptionObject.~MyError();
// normal code follows:
cout << "goodbye\n";
Because your compiler is failing to elide the copy from the temporary to the exception object managed by the exception handling mechanism.
Conceptually, MyError("hi") creates a temporary, which will be destroyed at the end of the statement (before the exception can be handled). throw copies the thrown value somewhere else, where it will persist until after the exception has been handled. If the thrown value is a temporary, then a decent compiler should elide the copy and initialise the thrown value directly; apparently, your compiler didn't do that.
My compiler (GCC 4.8.1) does a rather better job:
MyError::MyError()
hi
MyError::~MyError
goodbye
Your exception is being copied. If you instrument the copy ctor, you can see this:
#include <iostream>
#include <stdexcept>
#include <string>
using namespace std;
class MyError : public runtime_error
{
public:
MyError(MyError const &e) : runtime_error("copy") { std::cout << "Copy MyError"; }
MyError(string mess = "");
~MyError(void);
};
MyError::MyError(string mess) : runtime_error(mess) {
cout << "MyError::MyError()\n";
}
MyError::~MyError(void) {
cout << "MyError::~MyError\n";
}
int main(void) {
try {
throw MyError("hi");
}
catch (MyError& exc) {
cout << exc.what() << endl;
}
cout << "goodbye\n";
return 0;
}
Result:
MyError::MyError()
Copy MyError
MyError::~MyError
copy.what()
MyError::~MyError
goodbye