I have a hierarchy of objects, mostly connected by composition. I.e. (not showing the class methods for readability):

class A {}
class B {A a;}
class C {B b;}
class Z {Y y;}

class Z provides the API for executing commands from another program - a control panel. I think this is called Chain of Responsibility, but might be at an error.

Now when an action on A needs to be performed, Z calls a method of Y, because Z knows only about Y. So on, until we reach A, which has the proper members and methods to handle the request.

This has the fundamental problem that debugging becomes tedious - one has to step in many times, and each time be careful not to miss the actual working method - otherwise the debugging session needs to be restarted.

How do I make debugging more straightforward? A change in the architecture of a method of using gcc that is more suited to this situation?

  • 6
    use breakpoints in the A class? – ratchet freak Oct 31 '14 at 10:11
  • You can't, because the error might be in any of the classes. So you have to go through all the classes and search for the method call which get's the correct arguments but does not do or return what it should. There is no way around this. Unless you know from the beginning which method produced the wrong result. In this case, do like ratched freak said and use breakpoints there. Or even better: make class A so that it always returns the same result when given same arguments. You can then directly call A with these arguments and check the result. – valenterry Oct 31 '14 at 10:43
  • Would instead of writing wrappers, using using solve my problem? – Vorac Oct 31 '14 at 13:02

When you split up big methods into smaller ones, and separate concerns to many classes, and write more functions with clearly separated levels of abstraction, you will end up with long call chains, that's true. But when you choose your abstractions well your code becomes much more readable and understandable than the typical 200 lines-of-code-spagetthi function.

And readable code avoids a lot of bugs at first hand, so to my experience this outweighs the increased debugging efforts caused by the call chains by a multitude. So my advice is: live with it. Don't use this "long call chains make debugging harder" argument as an excuse for not refactoring your code into smaller functions, such reasoning leads always to a fallacy.

As a hint for debugging when you accidentally missed the cause of an error: some debuggers (like gdb) allow you to "undo" your last steps in the middle of a debugging session.

| improve this answer | |
  • In Visual Studio you can simply drag the "current instruction" arrow to you the line you want to execute next. – Johannes S. Oct 31 '14 at 12:40
  • @JohannesS.: you are correct, but the OP was talking about GCC, not about VS. – Doc Brown Oct 31 '14 at 13:01
  • 1
    Ah, sorry, missed this because I only had a quick look at the tags – Johannes S. Oct 31 '14 at 14:34

Use logging. (I don't know what are logging options in c++, but i would be surpirsed if there wasn't something close to what is available in Java).

Log entering and exiting method and what is going in/out (and either do it in configurable automatic way, or only in interesting places). This way you know where it went and if you can formulate postconditions and preconditions, you can check them when going through logs to find where something strange is happening and then put breakpoint to the right place.

When same method is called repeatedly and only after log run it breaks down on border case, you can use conditional breakpoint, because you know (from logs) what data causes problem.

This will require multiple runs to examine problem, but log run will be without manual steping, so much faster, and in debug run you will start closer to actuall problem (or at least its closer to its manifestation.

| improve this answer | |
  • It's an embedded project and storing and retrieving logs sounds problematic. We have a display, to which we write when an assert() fails. – Vorac Oct 31 '14 at 12:04
  • @Vorac: Especially in embedded devices logging is nearly indispensable. Usually there is a serial port used for debug output and you could send the logging there too and analyse it off-line. – Bart van Ingen Schenau Oct 31 '14 at 19:13
  • Unfortunately the HW guys are too lazy to connect the appropriate pins to a header. I have USB and JTAG available. – Vorac Nov 3 '14 at 12:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.