8
\$\begingroup\$
#include<iostream>
#include<string>
using namespace std;

// Generic class for tracing the function call
class functionlogging {
private:
    string name;
    string in{ ">>" };
    string out{ "<<" };
public:
    functionlogging(string x) :name(x) {
        cout << in << name << endl;
    }
    ~functionlogging(){
        cout << out << name << endl;
    }
};

//uses
void generic_function() {
    functionlogging logger{ __func__ };
    int a = 10;
    int b = 100;
    a += b;
}


int main() {
    generic_function();
}

Many times, we do need to log when function call starts and ends for better understanding. With modern C++ concepts like __funct__/RAII, I wrote the small class which can be used to achieve trace. With this I was able to achieve this for above "generic_function()".

Output

>>generic_function
<<generic_function

I wanted others opinion about the functionlogging class and how to make it in such a way that user of this class would have to do the minimal work/code changes in his/her code base.

At present user of this class needs to create a object of this class and pass the __func__ information. Is it acceptable or in a way can it be embed inside something by which user of the class almost do not require to do anything?.

\$\endgroup\$
  • \$\begingroup\$ You could use some preprocessor #define like with assert, if you like that more. \$\endgroup\$ – user52292 Oct 12 '14 at 16:41
  • \$\begingroup\$ I can't find a meaning for your class, sorry. A debugger just works better. \$\endgroup\$ – edmz Oct 12 '14 at 17:23
  • 3
    \$\begingroup\$ @black. That is neither true nor a useful statement. In a data driven program the call history will not be obvious and thus logging is needed to trace where the code has been before a crash point (a lot of that stack information may no longer be available in the core file). Also the comment does not help in any way review the code. \$\endgroup\$ – Martin York Oct 12 '14 at 17:31
  • \$\begingroup\$ @LokiAstari I'm looking for explainations which do help for a code review. Also, your example is questionably related. \$\endgroup\$ – edmz Oct 12 '14 at 17:45
  • 1
    \$\begingroup\$ If you don't want to post a new question to get further feedback, you can always post your updated code as an answer to help future readers. That's #3 in Jamal's link, and it seems to fit your stated goal best. \$\endgroup\$ – Brythan Oct 21 '14 at 5:05
8
\$\begingroup\$

Stop doing this:

using namespace std;

see: Why is “using namespace std;” considered bad practice?

These two are not unique to the class.

string in{ ">>" };
string out{ "<<" };

May as well make them static. Also they re never modified so make them const.

No need to force a flush with std::endl

    cout << in << name << endl;

Prefer "\n" when you don't need a flush (also cerr or clog may be better choices of output stream).

That seems like an overly verbose and error prone way of use.

void generic_function() {
    functionlogging logger{ __func__ };

You have to use up a variable and remember __func__. Can't we get a macro in here to do all the for you? I actually need to look up to see if func is a standard macro.

Just checked the standard:

8.4.1 In general
Paragrah 8:
The function-local predefined variable __func__ is defined as if a definition of the form  

static const char __func__[] = "function-name ";

So I would define the macros:

#define LOG_ENTRY_EXIT_FOR(x)       functionlogging  SomeLongNameThatIsNotLikelyToBeUsedInTheFunctionlogger(x)
#define LOG_ENTRY_EXIT              LOG_ENTRY_EXIT_FOR(__func__)

Then usage is simply:

void generic_function() {
    LOG_ENTRY_EXIT;

    int a = 10;
    int b = 100;
    a += b;
}
\$\endgroup\$
1
\$\begingroup\$

Just a minor addition. Storing (and passing) the function name in a const char* will eliminate the costly (dynamic memory allocation) construction of a string.

\$\endgroup\$
1
\$\begingroup\$

Sounds great. I would recommend a little improvement to Loki Astari's answer.

By changing the way you define LOG_ENTRY_EXIT,

#if defined(DEBUG)
#define LOG_ENTRY_EXIT   LOG_ENTRY_EXIT_FOR(__func__)
#else
#define LOG_ENTRY_EXIT
#endif

One will be able to compile it in or out for say release build if needed.

We use this type of tracing quite a lot in game development code.

\$\endgroup\$
  • \$\begingroup\$ If you're posting a comment to someone else's answer, but find it noteworthy enough to post as an answer, be sure to point out what answer you're referencing to. \$\endgroup\$ – Pimgd Feb 26 '16 at 11:04
  • \$\begingroup\$ I've edited your answer as an example; like this it's clearer where your contribution is coming from. When you get more reputation (50+), you'll be able to comment on other people's posts, after which you may want to write answers like this as comments instead. \$\endgroup\$ – Pimgd Feb 26 '16 at 11:08
0
\$\begingroup\$

The below is updated code after incorporating the suggestion in this post. This is just for easy reference for future reader.

  #include<iostream>
  #include<string>

    // Generic class for tracing the function call
    class functionlogging {
    private:
        std::string name;
        static std::string in;
        static std::string out;
    public:
        functionlogging(std::string x) :name(x) {
            std::cout << in << name <<"\n";
        }
        ~functionlogging(){
            std::cout << out << name <<"\n";
        }
    };

std::string functionlogging::in{ ">>" };
std::string functionlogging::out{ "<<" };


//Define MACRO for easy use for end user.
#define LOG_ENTRY_EXIT_FOR(x)       functionlogging  SomeLongNameThatIsNotLikelyToBeUsedInTheFunctionlogger(x)
#define LOG_ENTRY_EXIT              LOG_ENTRY_EXIT_FOR(__func__)


    //uses
    void generic_function() {
        LOG_ENTRY_EXIT;
        int a = 10;
        int b = 100;
        a += b;
    }


    int main() {
        generic_function();
    }
\$\endgroup\$

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.