Optimized away STL container's size

Viewed 83

While debugging an issue, I added some tracepoints printing the size() of an std::queue as

The size of the queue is {mQueue.size()}

but I see this message in the Output window

The size of the queue is Function std::queue<Foo>::size has no address, possibly due to compiler optimizations.

If I break into the code at that point, I do see the size

mQueue
    c: { size=0 }
    [Raw View]: {c={ size=0 } }

But again if I try mQueue.size() I see the same log

Function std::queue<Foo>::size has no address, possibly due to compiler optimizations.

Is there a way to get at the size() in the tracepoint rather than resorting to code changes to store the size in some variable and possibly printing that? I've tried wrapping the function where I've added the trace point within #pragma optimize( "", off ) but to no avail. Also I want to avoid changing the Linker option to /DEBUG:FULL if possible.

1 Answers

The compiler never has a need to generate code for std::queue<Foo>::size(), so it doesn't bother; so at runtime, the debugger doesn't have it to call.

One solution would be to explicitly instantiate the function, with something like template std::queue<int>::size_type std::queue<int>::size() in a source file. But that would require you to get the declaration exactly right, which would be quite a pain and would likely make the code compiler-specific and even standard-library-implementation-version-specific.

The other option is to just have a call to the appropriately typed size() somewhere in your code. Even in code that's never called.

Example:

#include <queue>

void thisIsNeverCalled()
{
    std::queue<int> q;
    (void)q.size(); // If this line is present, the below tracepoint works
}

int main()
{
    std::queue<int> q;

    for (int i = 0; i < 5; i++)
    {
        q.push(i); // can trace q.size() here if the above line is present
    }
}

(The (void) is just there to quash compiler warnings from the [[nodiscard]] attribute.)

Note that this approach is less likely to work with optimizations enabled. To mitigate that, surround thisIsNeverCalled with #pragma optimize, and potentially force the linker to include it with a suitable #pragma comment.

Related