8

I am working on a logging / tracing unit (and please don't point to existing ones, this is for the experience as much as for the result).

To get a run-time calling stack trace, the idea is to construct a TraceObject instance first thing a function is entered, which carries the information of the current class and function. Somewhat akin to:

TraceObject to( "MyClass", "myClassFunction" );

The constructor of TraceObject pushes this on a per-thread stack, the destructor pops it again. The stack can thus be queried for the call stack.

I got this working to satisfaction. However, there is a small snitch: The object to. It will, by design, never be referred to by that name. Hence, it does not need to have a name, least of all one that might collide with any identifiers used by the client (or, in case of _ prefix, the implementation).

tl;dr

Is it possible to create an anonymous, non-temporary object on the stack (i.e. one that will live until the function returns, but doesn't have an identifier), and if yes, how would it be done?

DevSolar
  • 67,862
  • 21
  • 134
  • 209
  • 3
    I dont think it is strictly possible, but with a macro and an obscure name, you can achieve the same. Is there a valid reason why you need it to be nameless or is it more of a "its not really required" thing. – Karthik T Mar 20 '13 at 08:16
  • @KarthikT: Yes, a wrapper macro was the general idea. I was just wondering if I could do away with "obscure" and achieve "invisible". – DevSolar Mar 20 '13 at 08:19
  • @Karthik T exactly, that's also how boost log does it so my guess is: there is no other way – stijn Mar 20 '13 at 08:19
  • Years ago the Unreal SDK had something similar, but also included a try/catch block. The name was made by a macro concatenating the class and function names, along with some other bits, if I remember correctly. – Peter Wood Mar 20 '13 at 08:20
  • No I don't think it's possible without an ugly macro hack. – Shoe Mar 20 '13 at 08:21

3 Answers3

5

No.

There are anonymous objects in C++, temporaries that are the results of expressions, however they only live in the context of the statement they are in.

If you actually attempt to declare an anonymous object, you will confuse the parser and it'll think you are declaring... a function!


But then, is it necessary ?

If you accept to use macros to actually declare the TraceObject, then it is as simple to use a macro for each trace; and thus provide the class and function there. Using __func__ or equivalent you can extract the class name and function name (bit of string parsing required, depends on the compiler) and work from there.

And of course, you would be using a macro for each trace anyway, because you would probably want the file name and line number!

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • you can prolong live time of temporary object with const reference, but const reference inself is another name of the temporary object: const T& r = T(); – AnatolyS Mar 20 '13 at 08:38
  • @AnatolyS: const-reference or rvalue-reference (in C++11), but yes, as you noted, it introduces an identifier anyway. – Matthieu M. Mar 20 '13 at 09:09
  • I don't like the `__func__` way as it's implementation defined. But you get the checkmark for actually answering the question, whether anonymous objects are possible ("No."). ;-) – DevSolar Mar 20 '13 at 09:32
  • @DevSolar: I must admit I'd really like to have a way to get the class name and function name in a Standard way. I don't really like `__func__` either, and generally I pass it to a function that is specifically defined to parse its output and extract the function name, the function being defined in a compiler-dependent way. – Matthieu M. Mar 20 '13 at 09:37
  • @MatthieuM.: ACK. I was actually surprised to find this wasn't rectified in C++11... – DevSolar Mar 20 '13 at 10:06
3

As I say in my comment, scope limited anonymous variables cannot be used.

#define BEGIN_LOG   TraceObject abcdefghij( "", __func__ );

void Function(){
    BEGIN_LOG;

    //bla bla

}

This should do it, provided there is a compiler macro to get Class name.

Edit: No Luck with a easy way to get class name, you might have to do something like what is suggested at Class name macro. Or just make do with __FILE__.

Edit: You might want to try __func__ and __FUNCTION__ to see if either or both work as you want them to. Neither are C++ standard specified.

Community
  • 1
  • 1
Karthik T
  • 31,456
  • 5
  • 68
  • 87
1

Some line number stuff:

#define XPASTE(arg1, arg2) PASTEX(arg1, arg2)
#define PASTEX(arg1, arg2) arg1 ## arg2
#define TRACELOG() \
            TraceObject XPASTE(trace_object,  __LINE__)
perreal
  • 94,503
  • 21
  • 155
  • 181
  • Not much obfuscation to be won by adding `__LINE__`, but at least you avoid "shadowing" warnings if a second `TraceObject` is created... – DevSolar Mar 20 '13 at 09:30