开发者

Coding for ease of debugging

I am looking for tips on how to aid my debugging by adding code to my application. An example so that it becomes more clear what I'm after: in order to detect dangling objects held by shared_ptrs I have created a tracker class that allows me to keep track of how many objects are alive and where they where originally created, which is then used like this:

class MyClass {
 开发者_如何学编程   TRACK_THIS_TYPE(MyClass);
};

boost::shared_ptr<MyClass> myObj(new MyClass);
TRACK_THIS_OBJECT(myObj);

where TRACK_THIS_TYPE(t) is a macro that makes sure that I get an instance count (and count of how many objects have been created) for a class and TRACK_THIS_OBJECT is a macro that stores the file and line where the object was created together with a weak_ptr to the object.

This allows me to detect dangling objects and where they where created. It does not allow me to find out what objects are holding a shared_ptr to my objects, which could be an improvement to the above. I guess one could create something like a TRACK_THIS_PTR(T) macro that would store the file and line for where the shared_ptr instance is created.

Another example would be the old

assert(condition && "My descriptive text");

that allows you to put meaningful comments directly into your assert.

Does anyone have any neat c++ tricks to collect stats, automatic stack traces, tracking of objects/pointers/resources, deadlock/starvation or other threading issues detection, making sure that exceptions get handled somewhere, documentation help or similar? Anything goes really, whether it is something that helps prevent errors or something that helps after the fact.

Edit: In addition to the replies to this question, I've received tips about google-glog as a logging utility.


I use BOOST_ASSERT a lot, to check input, intermediate calculations and before returns, even if it seems obvious.

It forces you to think about what values can take you data, and can make it easier to rapidly find out a refactoring that left some stupid error.

If you're really concerned about performances, you can disable them for a release build.

Concerning memory managing, I massively use RAII and try to do my best to use as few pointers and manual memory allocation as possible. When only having 2 or 3 pointers in your code, it's easier to avoid doing an error.


Interestingly we have quite a similar project at work in order to track memory issues.

Many people swear by RAII, but even using shared_ptr you can create leaks, the problem being mainly due to references cycles (that's why reference counted based garbage collectors have special algorithms to detect cycles) :x

The company I work for (Amadeus) is currently developping AMPolice which ressemble valgrind. It is still work in progress, especially in the documentation department.

As you can see, this is completely different from your own approach: The binary is left unchanged, and the memory allocation is tracked by switching to a "debug" memory management (at runtime) when necessary (using a command-line API).

This is therefore much easier to use, although from our tests it does affect timings (4x or 5x).

The tool is pretty generic, so normally could be used by many people, but of course the main issue remains the shear size of logs since tracing every single new is quite costly :x


The following are mainly for ease of debugging after the release.

Stackwalker and similar tools provide an easy way to get usable callstacks on end-user machines, with no debugger being active. Rather similar, Google Breakpad can be used to easily extract mini dumps from crashed processes.


You could look into logging the stats you are producing with something like "log4cxx"

http://logging.apache.org/log4cxx/index.html

This should let you control the level of tracing you are doing at runtime (or at least via a configuration file read in at runtime).

It will automatically timestamp your logging, and let you format your output to suit other tools (say Excel or a database) to allow you to do statistical analysis of your logging data.


I would personally prefer to aim at not writing bugs in the first place. Adding reams of debugging code to an application can have unfortunate side effects. It obviously affects performance and, in the case of multi-threaded apps, can change the timing of the application, resulting in MT bugs being hidden.

I find I normally spend very little time debugging my code - and any time I do spend in the debugger I count as time wasted. What I find does help is having tests I can run after every change I make - you don't have to embrace TDD to use this approach.


My c++ is a bit rusty now, but I do remember that whenever I had to allocate an object I had a macro that performed it something like:

NEW(class)

and then a macro for deallocation of objects called RELEASE. Then each macro would store the class and line number of where the object was created and destroyed.

This would allow easy detection of memory leaks by being able to see where objects were not being released.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜