Quite often I see the following pattern in C++:

int64_t getSomeValue()
    static int64_t cache = 0;
    if (cache)
        return cache;
    // expensive calculation with assigning the calculated value to the cache
    return cache;

While this approach might seem effective at first glance, it has several issues:

  1. Magic Value Zero: The code uses 0 as a magic value to indicate that the cache hasn’t been initialized. This can lead to unintended behavior if 0 is a valid result from the expensive calculation. Additionally, using magic values like this is generally considered poor practice as it relies on implicit knowledge.

  2. Not Leveraging Static Variable’s Reentry Protection: The static variable cache is initialized to 0, and the function checks if cache is non-zero to avoid recalculating. However, in C++, static variables are protected from concurrent reentry issues using a mutex during initialization. In the original pattern, the if statement checking cache is not protected with any mutex, so this pattern does not leverage the built-in protection provided by the language.

A better approach would be to use a lambda function for the initialization, like this:

auto getSomeValue()
    static auto cache = []() {
        return 314LL; // expensive calculation
    return cache;

With this code:

  1. No Magic Value: The initialization of the static variable cache is done directly through a lambda function that performs the expensive calculation. This avoids the need for a magic value and ensures that the actual result of the calculation is stored in the cache.

  2. Reentry Protection: By leveraging the static variable’s reentry protection, this code is cleaner and safer. The lambda function executes only once, and the resulting value is cached properly. Additionally, this version clearly communicates the intention of performing a one-time calculation.

  3. Improved Readability: In my opinion, this code is easier to read and understand. The use of the lambda function clarifies that the expensive calculation is only performed once, and the result is cached for future use. This clarity enhances maintainability and reduces potential bugs.

In conclusion, the lambda-based initialization pattern is not only cleaner but also takes full advantage of the safety features provided by C++. It’s an excellent way to handle expensive calculations that only need to be done once, while also avoiding the pitfalls of magic values and unnecessary reentry checks. Additionally, it makes the code more readable and understandable, which is always a bonus in software development.

The article was written with the help of ChatGPT 4.

Next - Previous