Why does this program
#include <clang-c/Index.h>
#include <exception>
#include <iostream>
int main() {
try {
throw std::exception("threw");
} catch (const std::exception& e) {
std::cout << e.what() << "\n";
}
CXIndex idx = clang_createIndex(0, 0);
clang_disposeIndex(idx);
return 0;
}
behave as expected, but this one
#include <clang-c/Index.h>
#include <exception>
#include <iostream>
int main() {
CXIndex idx = clang_createIndex(0, 0);
clang_disposeIndex(idx);
try {
throw std::exception("threw");
} catch (const std::exception& e) {
std::cout << e.what() << "\n";
}
return 0;
}
crashes?
More generally, what could a function do that causes subsequent exceptions to not get caught?
Using: visual c++ 10.0 (tried the different /EH flags), clang 3.4 (built with the same)
Related
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;
}
// Example program
#include <iostream>
#include <string>
#include <stdexcept>
void log(const std::exception& e) {
try {
throw e;
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl; // How to get logic_error back once caught?
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception& e) {
log(e);
}
}
I don't want to add more catch clauses is because I want to have a central place to log detailed exception message, it could be very different across different exceptions.
Is there a way to narrow down the std::exception to derived exception in the catch clause?
You can rethrow the original exception in your log method to preserve its original state. This way everything should work as you would expect it.
Modified log method looks like this:
void log(const std::exception& e) {
try {
throw;
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl;
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
See throw expression for more details on how throw e and throw differs in this example.
std::exception::what() is virtual. So you don't need to get back the original type to write the logs. You just have to ensure that what() is redefined for your custom exceptions that inherits std::exception.
This may become:
void log(const std::exception & e)
{
std::cout << e.what() << std::endl;
}
You might use std::rethrow_exception:
void log(std::exception_ptr eptr) {
try {
if (eptr) {
std::rethrow_exception(eptr);
}
}
catch (const std::logic_error& e1) {
std::cout << "logic_error: " << e1.what() << std::endl;
}
catch (const std::exception& e1) {
std::cout << "exception: " << e1.what() << std::endl;
}
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception&) { // or even catch (...)
log(std::current_exception());
}
}
You don't have to use only base exceptions provided by the standard library, you can make your own exception hierarchy with the methods you need.
#include <exception>
#include <string>
#include <iostream>
class MyBaseException: public std::exception
{
public:
virtual std::string output() const = 0;
/* Define methods you need here */
};
class MySpecificException : public MyBaseException
{
public:
const char* what() const noexcept override {return "error"; }
std::string output() const override { return "Specific debug output that I want"; }
};
int main(){
try{
throw MySpecificException{};
}catch(const MyBaseException& e){
std::cout << e.output() << '\n';
}catch(const std::exception& e) {
std::cout << e.what() << '\n';
}
}
You can use run time type information to get the type of the execption:
#include <iostream>
#include <string>
#include <stdexcept>
#include <typeinfo>
#if defined(__clang__) || defined(__GNUC__)
#include <cxxabi.h>
#endif
std::string getTypename(const std::exception& e)
{
#if defined(__clang__) || defined(__GNUC__)
// .name() returns a mangled name on gcc and clang
int status;
return abi::__cxa_demangle(typeid( e ).name(), 0, 0, &status);
#else
// visual studio returns a human readable name
return typeid( e ).name();
#endif
}
void log(const std::exception& e) {
std::cout << getTypename( e ) << ": " << e.what() << std::endl;
}
int main()
{
try {
throw std::logic_error("sth wrong");
}
catch (const std::exception& e) {
log(e);
}
}
The getTypename() method may not work on all platforms and you might need to adjust it to your needs. You might want to use boost::core::demangle rather than calling the gcc demangle API directly.
I am new to C++ and wondering how I could catch all possible errors that could happen in my program during run-time. This is for debugging reasons only. To solve possible errors, I would like to have a look at them first.
This would be my idea of how to catch possible errors in a program. I do not throw exceptions, but would like to catch possible errors directly.
#include <iostream>
#include <exception>
#include <stdexcept>
int doBadStuf(int i)
{
// go out of bounce, or make other mistakes
return 10 / i;
}
int main()
{
try
{
int i = doBadStuf(0);
}
catch (std::exception &e)
{
std::cerr << e.what() << '\n';
}
catch (...)
{
std::cerr << "something else";
}
}
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
Boost version: 1.61, GCC version 6.2.0, C++14
Exceptions inside a boost::async() call seem to lose their type, while it works correctly with std::async. Is there a fundamental difference between std::async and boost::async I'm missing?
The following code works (using std::async):
#include <iostream>
#include <stdexcept>
#include <future>
using namespace std;
struct MyException : std::exception {
const char* what() const noexcept override { return "message"; }
};
int main() {
try {
auto future = std::async(std::launch::async, [] { throw MyException(); });
future.get();
} catch (const MyException& e) {
cout << "MyException caught. Message: " << e.what() << endl;
} catch (const std::exception& e) {
cout << "std::exception caught. Message: " << e.what() << endl;
}
}
and outputs
$ g++ test.cpp -std=c++14 -lpthread -lboost_thread -lboost_system && ./a.out
MyException caught. Message: message
However, the following code (it's the same, just using boost::async instead of std::async) does not work as expected:
#include <iostream>
#include <stdexcept>
#include <boost/thread/future.hpp>
using namespace std;
struct MyException : std::exception {
const char* what() const noexcept override { return "message"; }
};
int main() {
try {
auto future = boost::async(boost::launch::async, [] { throw MyException(); });
future.get();
} catch (const MyException& e) {
cout << "MyException caught. Message: " << e.what() << endl;
} catch (const std::exception& e) {
cout << "std::exception caught. Message: " << e.what() << endl;
}
}
It outputs:
$ g++ test.cpp -std=c++14 -lpthread -lboost_thread -lboost_system && ./a.out
std::exception caught. Message: std::exception
It also doesn't work for boost::future::then continuations:
#include <iostream>
#include <stdexcept>
#define BOOST_THREAD_VERSION 4
#include <boost/thread/future.hpp>
using namespace std;
struct MyException : std::exception {
const char* what() const noexcept override { return "message"; }
};
int main() {
try {
auto future = boost::make_ready_future(3).then([](boost::future<int>) -> int { throw MyException(); });
future.get();
} catch (const MyException& e) {
cout << "MyException caught. Message: " << e.what() << endl;
} catch (const std::exception& e) {
cout << "std::exception caught. Message: " << e.what() << endl;
}
}
outputs:
$ g++ test.cpp -std=c++14 -lpthread -lboost_thread -lboost_system && ./a.out
std::exception caught. Message: std::exception
So the concrete type of the exception seems to be lost when crossing the thread boundary. However, it doesn't seem to be connected to threading, because according to my tests, the same is true for std::launch::deferred (which works fine) and boost::launch::deferred (which loses the exception type).