65.9K
CodeProject is changing. Read more.
Home

C++ Code Point Tracking

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.45/5 (5 votes)

Dec 19, 2013

CPOL

2 min read

viewsIcon

19991

downloadIcon

135

An ad hoc solution to mark and track code points in C++

Introduction

Although there shouldn't, there are times when it's uncertain which code points are run through during the execution of a program. There are many professional tools out there which range from static analysis to instrumented measures to get answers to such questions, but on some occasions, an ad hoc solution can be more effective.

Background

The approach to make this work is to make use of the pre program start initialization of static variables, but since all code points are in functions and therefore, the "static anker point" has to be put there somehow and so, the C++ feature of delayed initialization of static function variables has to be overcome.

This seems to be possible by adding an indirection through a template class (X) with a static member variable (progloc_) to enforce the initialization per template parameter which in turn is a wrapper struct which transports the needed information (_.FILE._ " at line " _.LINE._).

Putting this together, the most important code to achieve this could look like the following:

template <class T> class X {
public:
    static T progloc_;
};
template <class T> T X<T>::progloc_;

#define TRACE_CODE_POINT { \
    struct ProgLocation { \
    public: \
        std::string loc_; \
        ProgLocation() : loc_(std::string(__FILE__ " at line " S__LINE__)) \
        { \
            TestFw::CodePoints::Test::imHere(loc_); \
        } \
    }; \
    TestFw::CodePoints::X<ProgLocation>  dummy; \
    TestFw::CodePoints::Test::iGotCalled(dummy.progloc_.loc_); }

The S_._LINE_._ - trick which is used in the ProgLocation - ctor comes from here on SO.

#define S(x) #x
#define S_(x) S(x)
#define S__LINE__ S_(__LINE__)

To track, the following is used:

class Test
{
private:
    typedef std::set<std::string> TFuncs;
    static TFuncs registeredFunctions;
    static TFuncs calledFunctions;
public:
    static int imHere(const std::string fileAndLine)
    {
        assert(registeredFunctions.find(fileAndLine) == registeredFunctions.end());
        registeredFunctions.insert(fileAndLine);
        return 0;
    }
    static void iGotCalled(const std::string fileAndLine)
    {
        if (calledFunctions.find(fileAndLine) == calledFunctions.end())
            calledFunctions.insert(fileAndLine);
    }
    static void report()
    {
        for (TFuncs::const_iterator rfIt = registeredFunctions.begin(); 
            rfIt != registeredFunctions.end(); ++rfIt)
            if (calledFunctions.find(*rfIt) == calledFunctions.end())
                std::cout << (*rfIt) << " didn't get called" << std::endl;
    }
};

Using the Code

All it needs to track a code point is to put the macro:

TRACE_CODE_POINT  

at the desired places and to call the report() method of the Test class at the end of the program.

Points of Interest

The provided solution is very dangerous for several reasons and should be used with care. Neither performance nor thread safety were considered. So far, the code has only been tested on MSVC 2010 and 2013.

If you're going to use the code, you might also consider adding some dispatching to the report method. The sample source provided in the zip at the start of the tip contains one such reporter and a console and a debug output window sink and also a handy helper to frame the main function.

History

  • 2013/12/20: First release