C26441 NO_UNNAMED_GUARDS

"Guard objects must be named."

C++ Core Guidelines: CP.44: Remember to name your lock_guards and unique_locks

The standard library provides a few useful classes which help to control concurrent access to resources. Objects of such types lock exclusive access for the duration of their lifetime. This implies that every lock object must be named, i.e. have clearly defined lifetime which spans through the period in which access operations are executed. So, failing to assign a lock object to a variable is a mistake which is effectively disables locking mechanism (because temporary variables are transient). This rule tries to catch simple cases of such unintended behavior.

Remarks

  • Only standard lock types are tracked: std::scoped_lock, std::unique_lock, and std::lock_quard.
    • Only simple calls to constructors are analyzed. More complex initializer expression may lead to inaccurate results, but this is rather an unusual scenario.
    • Locks passed as arguments to function calls or returned as results of function calls are ignored.
    • Locks created as temporaries but assigned to named references to extend their lifetime are ignored. ## Example missing scoped variable
void print_diagnostic(gsl::string_span<> text)
{
    auto stream = get_diagnostic_stream();
    if (stream)
    {
        std::lock_guard<std::mutex>{ diagnostic_mutex_ }; // C26441
        write_line(stream, text);
        // ...
    }
}

Example

missing scoped variable - corrected

void print_diagnostic(gsl::string_span<> text)
{
    auto stream = get_diagnostic_stream();
    if (stream)
    {
        std::lock_guard<std::mutex> lock{ diagnostic_mutex_ };
        write_line(stream, text);
        // ...
    }
}