Preventing deconstruction of anonymous variable defined in macro until end of scope

117 views Asked by At

I'm trying to leverage class constructors and deconstructors to represent and format scope in my log files via the RAII idiom. Using a single #define, it prints "{" and increases the global indentation level so that the next logged line is printed at that indentation level.

LogScopeRAII is supposed to print the "}" and decrease the global indentation level naturally as it goes out of scope at the end of Foo(). However, the behavior I am seeing is that LogScopeRAII is deconstructed immediately after being constructed.

Hypothesis: I think the problem is that LogScopeRAII is being created on the RHS of the assignment (and thus anonymously?) and is being destroyed at the end of the line, but I'm not sure what to do about. I thought LOG_ANONYMOUS_VARIABLE in VSCOPE_F would have done the trick and caused it to stick around, but it isn't.

Question: How can I stop LogScopeRAII from being deconstructed until the calling function goes out of scope?

/* Header */
LogScopeRAII::LogScopeRAII(Verbosity verbosity, const char* file, unsigned line, const char* format, ...)
{
    // ...
    // print "{" and then increase an indentation global var
}

LogScopeRAII::~LogScopeRAII()
{
    // ...
    // print "}" and then decrease the indentation global var
}

#define LOG_ANOMYMOUS_VARIABLE(str) LOG_CONCAT(str, __LINE__)

#define VSCOPE_F(verbosity, ...) \
LogScopeRAII LOG_ANONYMOUS_VARIABLE(raii) = \
((verbosity) > verb_cutoff() ? LogScopeRAII() : LogScopeRAII{verbosity, __FILE__, __LINE__, __VA_ARGS__}

#define SCOPE_F(verbosity_name, ...) VSCOPE_F(Verbosity_ ## verbosity_name, __VA_ARGS__)

#define SCOPE_FUNCTION(INFO) SCOPE_F(verbosity_name, __FUNCTION__)

/* Implementation */
void Foo()
{
    SCOPE_FUNCTION(INFO) // print "{" and increase indentation
    for (size_t i = 0; i < 3; ++i)
    {
        // do work
        LOG(INFO, "Work logged");
    }
    // print "}" and decrease indentation
}

Desired output:

{ Foo()
    "Work Logged" // Note indentation
} 0.23 s: Foo()

EDIT: BOILED THE ISSUE DOWN

The crux of it is this: The ternary doesn't seem to be working.

This works:

LogScopeRAII a(LogScopeRAII{ Verbosity_INFO, __FILE__, static_cast<unsigned>(__LINE__), "" });

But this does not:

LogScopeRAII a(((Verbosity_INFO) > indent) ? LogScopeRAII() : LogScopeRAII{ Verbosity_INFO, __FILE__, static_cast<unsigned>(__LINE__), "" });

I get:

{
}
Work logged
Work logged
Work logged
}
constructCounter: 1
destructCounter: 2
Exiting...
1

There are 1 answers

2
Jarod42 On BEST ANSWER
#define VSCOPE_F(verbosity, ...) \
LogScopeRAII LOG_ANONYMOUS_VARIABLE(raii) = \
((verbosity) > verb_cutoff() ? LogScopeRAII() : LogScopeRAII{verbosity, __FILE__, __LINE__, __VA_ARGS__}

should be

#define VSCOPE_F(verbosity, ...) \
LogScopeRAII LOG_ANONYMOUS_VARIABLE(raii) \
(((verbosity) > verb_cutoff() ? LogScopeRAII() : LogScopeRAII{verbosity, __FILE__, __LINE__, __VA_ARGS__})

else you use copy constructor of temporary variable.

(You might also fix you move-constructor and destructor to allow your current MACRO)