Just a day after publishing a warning about usage of const members
I finally was able to root-cause a huge memory regression in one of our services. To illustrate a problem, let’s play find the difference game. Here are 2 snippets of code
and
Attentive readers immediately noticed the only difference - in the first snippet tracer member is const and in the second - it’s not. Well, we are telling the compiler to generate move and copy constructors, so as long as it compiles, everything should be fine, right? Well, let’s compare the generated assembly
and
Noticed, the difference? You’re right - we still use a copy for the version with const Tracer member! Compiler cannot move the const member, since it cannot take its guts out, but instead of complaining, it simply uses a copy instead of move and everyone is happy, well, almost. And no, enabling pedantic warnings doesn’t help - both snippets above have 0 warnings from clang.
There are many approaches we can use to protect ourselves against this issue but if usage of move is important for your use-case, I recommend using a good old unit test. Unfortunately standard library doesn’t come with a convenience class for constructor invocation counting, but it’s easy to extend a naive Tracer class from my sample to serve your needs.