_- Faster C++

How to debug a program throwing an exception?

Posted on

Have you ever been confronted to a C++ exception that is hard to trace back? One of the problem with debugging C++ exceptions - at least with GDB - is that upon a throw, it directly jumps to the stack unwinding. Which is kind of confusing since the stack variables destroyed at that moment can be quite far from the throw instruction. And it leaves you without any information about the state of the stack at the moment of the throw. For instance, in the following toy example, an exception is thrown when a complex condition is met.

#include <exception> #include <string> #include <iostream> using std::exception; using std::string; using std::cerr; using std::endl; class MyException : public exception { string s; public: MyException(const string &_s) : exception(), s(_s) { } const char* what() const noexcept { return s.c_str(); } }; void f(int i) { static int j = 2; j *= (i%3 + 1); if(((i+j) & 0xFFF) == 2077) { // Complex condition throw MyException("Big error!"); } } int main() { for (int i = 1; i < 50; ++i) { f(i); } return 0; }

Running the debugger directly just causes an exit without any backtrace available. Besides, a step-by-step execution is very time-consuming because (Spoiler!) the throw happens at the 29th iteration! It would be cool to have GDB run and prompt only when the exception is thrown, wouldn't it? The easiest way to do so is by placing a breakpoint at the constructor of the exception class. For instance, you could place a breakpoint like the following:

break MyException::MyException( std::__cxx11::basic_string< char, std::char_traits, std::allocator > const&)

Or simply:

break MyException::MyException

Next time you run the program and it throws an instance of MyException, this simple trick will make GDB break and prompt you before the actual throw. This will allow you to examine the backtrace:

backtrace [full]

Then, going to "frame 1" will certainly be a very good starting point to further investigations to trace the root cause ;) Of course with the small example given here you could also set a breakpoint using the line number. But this technique does not scale up on big codebases, where an exception could originate from multiple locations. Those line-based breakpoints would be painful to set up. Alternatively, you could use a catchpoint:

catch throw

But this method also has its limits. It would prompt every time an exception is thrown, even if it is not the one you are interested in. Finally, if your C++ runtime (e.g. libstdc++) supports it, you could use the following catchpoint syntax to specify the exact type of exception you want GDB to stop upon:

catch throw MyException

The burden of compilation time

Posted on

For the sake of brevity, in this post I will just name "compilation" what would otherwise be named "compilation and linkage". Then the C++ workflow just consists in cyclic "compile and run" iterations. But compilation has nothing to do with the actual problem your are trying to solve with your program. It is just a step required by the C++ language. With no added value whatsoever. A lot of languages don't even need compilation! How many times a day do you compile your code? And especially, how much time does compilation cost you overall? Only a few minutes a day? Good news, you are fine! An hour or more? That would be really worth questionning! C++ programs are prone to require big compilation times. In fact, this is one of the reason that had Google develop the Go language in the first place! The web page linked here above gives clues as to how we can get faster compilation times in C++ projects. The problem in C++ has a variety of factors. One of which is templates. Precisely, their poor integration with the compilation model. There is an aweful lot to say about templates in general. They are very powerful tools for code reusability. In other words, productivity. But they induce such a bloat of the compilation time that it may actually counterweight that advantage! One way to mitigate the bloat is by declaring only the required code in each translation unit (e.g. each .cpp file). The definitions of the template functions or methods can be split up across one or many .inl files (NB: .inl stands for "inline"). Those can be included just like header files. Then, you could include only the required files for the template methods you actually call, and leave the rest not included. This way, you will reduce the charge of your compiler, and keep the .o object files has small as possible. With the benefit of faster linkage time as well. Please note that some developers name those files ".tpp" or ".txx" instead. But it actually does not matter at all to the compiler.



Copyright © 2022-2026
Créé par Janahan Nallanathan