Reputation: 190709
With python, when an exception occurs, I get detailed information about what file raised an error, even without a catch:
def hello():
raise Exception;
hello()
Execution result >>
Traceback (most recent call last):
File "exceptionExample.py", line 4, in <module>
hello()
File "exceptionExample.py", line 2, in hello
raise Exception;
Exception
With C++, the information is not that useful:
#include <iostream>
using namespace std;
class Error
{
};
int value()
{
throw Error();
}
int main(int argc, char *argv[]) {
value();
}
>>
terminate called after throwing an instance of 'Error'
Run Command: line 1: 52772 Abort trap: 6 ./"$2" "${@:3}"
How can I make C++ give more detailed information about what module raised an error and from which line?
I'd like to use it without a catch clause.
Upvotes: 4
Views: 1104
Reputation: 3149
Using standard C++11 one can thankfully obtain something quite similar to the Python backtrace, using:
std::nested_exception
and std::throw_with_nested
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Note that you have to wrap all functions which you want to appear in your backtrace in try/catch
and you need nonstandard macros (__FILE__
, __func__
, __LINE__
) to automatically add source location information.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace! You may also take a look at my MWE on GitHub or my "trace" library, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Upvotes: 0
Reputation: 2389
You could use the __FILE__
and __LINE__
definitions in your exception message.
For example:
#include <stdexcept>
class Error : public std::runtime_error
{
public:
Error (const std::string &message)
: std::runtime_error(message)
{}
};
int value()
{
std::stringstream ss;
ss << "Issues at " << __FILE__ << " on line " << __LINE__;
throw Error(ss.str());
}
In this example, I made Error
inherit from std::runtime_error
(which has a constructor to allow you to pass a message as a string)...
Additionally, take a look at this SO question: Global Exception Handling - note the answer about using the set_terminate
function. This will allow you to install a global handler that ensures the message is printed as you want. Here's some info on set_terminate().
Python gives a stack trace for an uncaught exception. The answer I've provided only tells you the file and line number. If you need a stack trace, several commenters have referenced some other SO questions that give advice on how to do this in C++. Beware of non-standard solutions to this issue, however.
Upvotes: 3
Reputation: 114461
There is no portable way to get the stack trace, a trick is to use an object in function context to save the information
struct StackTraceInfo {
const char *filename;
int line;
static std::vector<StackTraceInfo *> stack;
StackTraceInfo(const char *filename, int line) :
filename(filename), line(line)
{
stack.push_back(this);
}
~StackTraceInfo()
{
stack.pop_back();
}
};
#define ENTER StackTraceInfo(__FILE__, __LINE__) sinfo_;
The in every function just add a line with ENTER
at the very start of the body
int foo() {
ENTER
....
return 42;
}
in case of an exception before throwing you need to save the current stack trace using the content of global StackTraceInfo::stack
vector so who displays the message can access this information. Note that you cannot access the stack information in the exception handler because the stack has been already unwound at that point.
Note also that if your application is multithreaded you need using a separate stack for each thread using tread local storage instead of a global.
Upvotes: 0
Reputation: 70929
You can create your exceptions so that they wrap the stack trace when they are created. Still please take care only to log this in debug mode as logging stack trace may be a security concern.
Also using a debugger may help you.
Upvotes: 0