libcwd: The C++ Debugging Support Library - Reference Manual
Author: Carlo Wood
Description: C++ debugging support library with ostream debug output
Keywords: libcwd, debug output, debug facility, debug channel, object orientation, OO, C++, nested debug output, ostream, memory allocation, debugging, source file and line number

Main Page Reference Manual Namespace List Compound List Namespace Members Compound Members File Members

# Function objects

...

## Defining and initializing `Function` objects

#### Defining

`Function` objects need to be defined as static or global objects otherwise they will be re-initialized every time you call the `Function::init()` method.

    Function f1;                    // Global `Function' instance.

    void f()
    {
      static Function f2;           // Static `Function' instance.
      f2.init();
    }

Each `Function` instance needs to be initialized at least once before it can be used. There are several ways to do this all of which use the overloaded `Function::init()` method.

When you try to use an uninitialized `Function` object, the program will fail by default (exit with an error message). If you don't want that then you can add a flag to its constructor:

    Function f1(Function::nofail);

#### Initializing

First of all, it is possible to assign the current function to a `Function` object like so:

    void f()
    {
      f1.init();                                    // f1 represents the current function, f().
      // ...
    }

If this function is a template function (or a method in a templated class) then it is possible that it covers more than one instance. Therefore, in the case of a template you need to make the function object a static instance inside the template function: this will lead to one instance per template function instantiation.

In order to be able to refer to it later in that case you must use another `Function` to alias for the static instance:

    template<typename T>
      void f(T const& a)
      {
        static Function sf;                         // Do NOT call sf.init()!
        f1.init(sf);                                // f1 represents all `void f<T>(T const&)'
                                                    //   template function instantiations that
        // ...                                      //   have been called so far.
      }

Note that in this case the static object must not be initialized!

#### Searches

If you need to refer to functions that are not called yet, or when those functions are part of third party libraries, then you'll need to use search routines. These are much slower, especially the ones that use the demangled names; but each lookup will be done only once.

The following examples demonstrate several ways to search for function symbols. These initialization calls are best put early in main() of course. All of them will print debug output about what they are looking up and what they found. By default they will fail when nothing is found.

      f1.init(Function::regexp("^int g(.*)$"));       // f1 represents all functions 'g' returning an int.

      f1.init(Function::exactmatch("int h(void)"));   // f1 represents the function 'int h()'.

      f1.init(Function::mangled("_ZTv0_n12_NSoD0Ev"); // Look up by mangled name (exact matches only).

The `mangled` lookup is the fastest. It looks for both, C++ as well as C functions, so you could use it to look for C functions skipping the cpu intensive demangling that way. However, you can also specifically specify that the function you are looking for has C linkage by passing a flag to the search.

Flags are always the right-most parameter.

      f1.init(Function::regexp("malloc"), Function::c_linkage);

`regexp` and `exactmatch` look only for C++ functions by default.

#### Labels

It's possible to link an arbitrary label (an unsigned integer constant) to a `Function` object. This can be useful when you want to specifically mark a `Function` temporarily; you are allowed to reassign labels and/or remove the labels again.

For example,

    // Add this to debug.h.
    enum function_labels {
      f_x,
      f_y
    };

    // Elsewhere...
    void f()
    {
      f1.init();                                    // f1 represents the current function
      f1.label(f_x);                                //   and assign the label f_x to it.

      x();

      f1.label(f_y);                                // Change the label, setting it to f_y.

      y();

      f1.rmlabel();
    }

Functions x() and y() can retrieve the label set on f1, and as such find out whether this function (f1) called x() or y(). This might be needed when for example x() also calls y().

Important: The label is not removed when you exit function f()! You'll have to explicitely do so yourself if you want to keep track of the fact that the current function exited (otherwise subsequential calls to y() could think that it still was called from f()).