C++: When does std::future.set_exception() cause exception? - c++

The following code will print 0 and ends:
// version 1
#include<future>
#include<iostream>
using namespace std;
int main(){
promise<int> p;
auto f = p.get_future();
p.set_exception(current_exception());
try {
cout << f.get() << endl;
} catch (const exception& e) {
cout << "caught future set exception\n";
}
return 0;
}
Well, seems p.set_exception(current_exception()); didn't cause any issue. But when I change it to be:
// version 2
#include<cassert>
#include<future>
#include<iostream>
using namespace std;
int main(){
promise<int> p;
auto f = p.get_future();
string msg = "test promise";
async([&] { // new code which version 1 didn't have
try {
throw runtime_error(msg);
} catch (...) {
cout << "caught exception 1\n";
try {
p.set_exception(current_exception());
} catch (...) {
cout << "caught exception 2\n";
}
}
}).wait(); // end new code
try {
cout << f.get() << endl;
} catch (const exception& e) {
cout << "caught future set exception\n";
assert(e.what() == msg);
}
return 0;
}
It will run and print:
caught exception 1
caught future set exception
Just wonder how/when does a std::promise fall into error/exception state so that its get_future().get() will throw exception?
What's the main reason of my version 2 code that p.set_exception() causes f.get() issue, while version 1 code has no problem?
Thanks.

Related

Why `std::invalid_argument` is not caught with no-rtti in macOS M1 environment?

Today I met a weird behaviour in catching exceptions in C++, could anyone clarify it to me? Code snippe
#include <iostream>
#include <string>
#include <exception>
int main() {
try {
std::stod("notanumber");
} catch (const std::invalid_argument&) {
std::cerr << "std::invalid_argument" << std::endl;
} catch (const std::out_of_range&) {
std::cerr << "std::out_of_range" << std::endl;
} catch (const std::exception&) {
std::cerr << "Caught by ancestor" << std::endl;
} catch (...) {
auto ptr = std::current_exception();
auto type = __cxxabiv1::__cxa_current_exception_type();
std::cerr << type->name() << std::endl;
std::cerr << "..." << std::endl;
}
return 0;
}
Writes to output
St16invalid_argument
...
Environment details
C++ 14, disabled RTTI
Clang 13.1.6 arm64-apple-darwin-21.6.0
macOS Monterey 12.6
I expect exception to be caught on the very first catch block
Upd. Even simplest catch doesn't work for me on the environment
try {
std::stod("notanumber");
} catch (const std::invalid_argument&) { // not caught
std::cerr << "std::invalid_argument" << std::endl;
}

What error in my code I have which cause exceptions ignored?

I am Implementing some program error exception catching and it's not getting to work properly thus I have seen any error in my code and compiler is also not showing any warnings and error.
The programs build successfully but ignored the exceptions.
#include <iostream>
#include <string>
using namespace std;
void wrongUsage()
{
bool erroCode = true;
bool errorMessge = true;
bool stringError = true;
if(erroCode)
{
throw 7;
}else if (errorMessge)
{
throw "Something went wrong in Character message";
}else if(stringError)
{
throw string ("Something else wrong happened in the string area");
}
}
void programErrorExceptions()
{
void wrongUsage();
}
int main()
{
try {
programErrorExceptions();
}
catch (int err)
{
cout << "Code Exception occurred: " << err << '\n';
}
catch (char const *err)
{
cout << "Msg Exception occurred: " << err << '\n';
}
catch (string &err)
{
cout << "Strmsg Exception occurred: " << err << '\n';
}
return 0;
}
correct the following
void programErrorExceptions()
{
void wrongUsage();
}
to
void programErrorExceptions()
{
wrongUsage();
}

C++ Getting Location of std::out_of_range Exceptions

I'm working on a fairly lengthy program, and after running fine for awhile, suddenly I'm getting:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr
Being new to exception handling, I did some research and found that I would likely get more information by adding the following to my main function:
int main(int argc, char **argv){
try{
//stuff
}
catch(exception const &exc){
cerr << "Caught exception: " << exc.what() << endl;
}
}
The result of this is the following output:
Caught exception: basic_string::substr
This isn't any more useful than the default output; it doesn't tell me anything about the line triggering the core dump (there are many substr calls in my program), the data the substr is attempting to process, etc. Is there a method for displaying information such as this in C++, or is my only option to use a debugger such as gdb?
There are a few ways.
As you said, a debugger - but that won't help you once the code is in production.
Nested exceptions and function try blocks. e.g.:
#include <exception>
#include <stdexcept>
#include <iostream>
#include <sstream>
#include <iomanip>
void bar(std::string& s, int i)
try
{
s.at(i) = 'A';
}
catch(...)
{
std::ostringstream ss;
ss << "error in bar(" << std::quoted(s) << ", " << i << ")";
std::throw_with_nested(std::runtime_error(ss.str()));
}
void foo(std::string& s)
try
{
bar(s, 6);
}
catch(...)
{
std::ostringstream ss;
ss << "error in foo(" << std::quoted(s) << ")";
std::throw_with_nested(std::runtime_error(ss.str()));
}
void stuff()
try
{
std::string s;
foo(s);
}
catch(...)
{
std::throw_with_nested(std::runtime_error("error in stuff()"));
}
void print_exception(std::ostream& os, const std::exception& e, int level = 0)
{
os << std::string(level, ' ') << "exception: " << e.what() << '\n';
try {
std::rethrow_if_nested(e);
} catch(const std::exception& e) {
print_exception(os, e, level+1);
} catch(...) {}
}
int main()
{
try{
stuff();
}
catch(std::exception& e)
{
print_exception(std::cerr, e);
return 127;
}
return 0;
}
sample output:
exception: error in stuff()
exception: error in foo("")
exception: error in bar("", 6)
exception: basic_string::at: __n (which is 6) >= this->size() (which is 0)
You could use boost::stacktrace in place of the above nested exception handling.
http://coliru.stacked-crooked.com/a/f21bd35632a0a036

throwing exception from thread is not giving expected results

In below code snippet i am trying to catch the exception after re-throwing the same but couldn't achieve the same . I am not sure what went wrong though as i already have preserved current teptr state through current_exception(). Thread is running in continuous loop so once its value reaches to the greater 2 then catch block is executed and control reaches out of the loop but still as expected i am not able to reach the other catch block in first attempt itself.
#include <boost/thread.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
#include <boost/exception/all.hpp>
#include <exception>
using namespace std;
boost::exception_ptr teptr;
class myexception : public exception
{
virtual const char* what() const throw()
{
return "My exception happened";
}
} myex;
class ABC
{
public:
void start();
};
void ABC::start()
{
int i = 0;
cout << "running the thread" << std::endl;
while (1)
{
try
{
std::cout << "value of " << i << '\n';
if (i > 2)
{
throw boost::enable_current_exception(myex);
}
i++;
}
catch (exception& e)
{
cout << "actual exception is" << e.what() << '\n';
teptr = boost::current_exception();
break;
//throw myex;
}
}
}
int main()
{
ABC abc;
boost::thread thread_point;
while (1)
{
boost::thread thread_point;
thread_point = boost::thread(&ABC::start, abc);
if (teptr) {
try {
boost::rethrow_exception(teptr);
}
catch (const std::exception &ex)
{
std::cerr << "Thread exited with exception: " << ex.what() << "\n";
exit(0);
}
}
}
}
Your program access the variable teptr (as well as myex) from multiple threads simultaneously without synchronization. The behaviour is UNDEFINED.
What's worse, you're shadowing thread_point and creating many threads that aren't joined. You're literally running unlimited threads sharing the same global data.
I suppose you're really looking for futures - that allow you to return a value or an exception from wherever. All the exception handling magic is done for you:
Live On Coliru
#include <thread>
#include <future>
#include <iostream>
#include <sstream>
struct ABC {
int task(int until) {
for (int i = 0; i<10; ++i) {
if (i > until) {
std::ostringstream oss;
oss << "My exception happened in thread " << std::this_thread::get_id() << " at i=" << i;
throw std::runtime_error(oss.str());
}
}
return 42;
}
};
int main() {
for (int runs = 0; runs < 10; ++runs) {
ABC abc;
std::future<int> result = std::async(&ABC::task, &abc, rand()%20);
try {
std::cout << "Task returned " << result.get() << "\n";
} catch (const std::exception &ex) {
std::cout << "Task exited with exception: " << ex.what() << "\n";
std::cerr << "Thread exited with exception: " << ex.what() << "\n";
}
}
}
Prints (e.g.):
Task returned Task exited with exception: My exception happened in thread 140288972076800 at i=4
Thread exited with exception: My exception happened in thread 140288972076800 at i=4
Task returned Task exited with exception: My exception happened in thread 140288972076800 at i=7
Thread exited with exception: My exception happened in thread 140288972076800 at i=7
Task returned 42
Task returned 42
Task returned 42
Task returned 42
Task returned Task exited with exception: My exception happened in thread 140288972076800 at i=7
Thread exited with exception: My exception happened in thread 140288972076800 at i=7
Task returned 42
Task returned 42
Task returned Task exited with exception: My exception happened in thread 140288972076800 at i=2
Thread exited with exception: My exception happened in thread 140288972076800 at i=2
Update My answer is deficient and with error, see sehe's comment.
I'm not sure what your end goal is here but to figure out how to handle a throw from a thread. Yes, you can get around the compilers inability to throw between threads with Boost Exception.
#include <boost/thread.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
#include <boost/exception/all.hpp>
#include <exception>
boost::exception_ptr teptr;
class myexception: public std::exception
{
virtual const char* what() const throw()
{
return "My exception happened";
}
} myex;
class ABCc
{
public:
void start();
};
void ABCc::start()
{
int i=0;
std::cout<<"running the thread"<<std::endl;
while (1)
{
try
{
std::cout << "value of "<<i << '\n';
if(i>2)
{
throw boost::enable_current_exception(myex);
}
i++;
}
catch (std::exception& e)
{
std::cout << "actual exception is"<<e.what() << '\n';
teptr=boost::current_exception();
break;
// where were you going here???????
//throw myex;
}
}
}
int main()
{
ABCc abc;
boost::thread thread_point;
thread_point = boost::thread(&ABCc::start,abc);
while(1)
{
if (teptr) {
try {
boost::rethrow_exception(teptr);
}
catch(const std::exception &ex) {
std::cerr << "Thread may have exited; exception thrown: " << ex.what() << "\n";
break;
}
}
}
std::cout << "exception should have been caught" << std::endl;
return 0;
}
Note that you do not have to throw/catch in main. You were creating multiple threads by having boost::thread inside your loop, was that your intention?

std::future::get() does not catch the exception when the async function throws and program crashes

I am trying to call the future::get() function from the function started using the std::async function. In the async function I am throwing so that I can catch the exception in the future::get() call. However, I get an exception in the get() call that is not caught in the catch bloc and the program crashes with unhandeld exception. What am I missing ?
#include "stdafx.h"
#include <iostream>
#include <future>
void AsyncMethodThrowsExceptionTest();
void AsyncMethodThrowsException();
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
AsyncMethodThrowsExceptionTest();
return 0;
}
void AsyncMethodThrowsExceptionTest()
{
std::future<int> executionFuture;
try
{
executionFuture = async(launch::async, AsyncMethodThrowsException);
}
catch(...)
{
cout << "caught ex [1]";
}
std::future_status::future_status status;
status = executionFuture.wait_for(std::chrono::milliseconds(500u));
if(status == std::future_status::deferred)
{
cout << "AsyncMethodThrowsException has not started";
}
else if(status == std::future_status::timeout)
{
cout << "AsyncMethodThrowsException timed out";
}
else if(status == std::future_status::ready)
{
cout << "AsyncMethodThrowsException successfully completed";
try
{
if(executionFuture.valid())
{
executionFuture.get();
}
}
catch(const std::future_error& ex)
{
cout << "AsyncMethodThrowsExceptionTest catch block";
}
}
}
void AsyncMethodThrowsException()
{
throw(new exception("Exception from AsyncMethodThrowsException"));
}
Not only are you throwing a pointer to a std::exception in AsyncMethodThrowsException (there's no reason to do this), you're both catching a reference to an exception not a pointer, and a reference to a child class of std::exception at that; std::future::get() throws the exact exception thrown in the called function, not a std::future_error.
There are a couple of other syntax issues:
std::future<int> executionFuture should be std::future<void> executionFuture
std::future_status::future_status status should be std::future_status status.
std::exception does not have a constructor that takes a char const* or a std::string, this might be a compiler extension.
To sum things up:
#include <iostream>
#include <future>
void AsyncMethodThrowsExceptionTest();
void AsyncMethodThrowsException();
using namespace std;
int main()
{
AsyncMethodThrowsExceptionTest();
}
void AsyncMethodThrowsExceptionTest()
{
std::future<void> executionFuture;
try
{
executionFuture = async(launch::async, AsyncMethodThrowsException);
}
catch (...)
{
cout << "caught ex [1]";
}
std::future_status status = executionFuture.wait_for(std::chrono::milliseconds(500u));
if (status == std::future_status::deferred)
{
cout << "AsyncMethodThrowsException has not started";
}
else if (status == std::future_status::timeout)
{
cout << "AsyncMethodThrowsException timed out";
}
else if (status == std::future_status::ready)
{
cout << "AsyncMethodThrowsException successfully completed";
try
{
if(executionFuture.valid())
{
executionFuture.get();
}
}
catch(const std::exception& ex)
{
cout << "AsyncMethodThrowsExceptionTest catch block";
}
}
}
void AsyncMethodThrowsException()
{
throw runtime_error("Exception from AsyncMethodThrowsException");
}