Warning C26448

Consider using gsl::finally if final action is intended (gsl.util)

C++ Core Guidelines: GSL.util: Utilities

The Guidelines Support Library provides a convenient utility to implement the final action concept. Since the C++ language doesn't support try-finally constructs, it became common to implement custom cleanup types that would invoke arbitrary actions on destruction. The gsl::finally utility is implemented in this way and provides a more uniform way to perform final actions across a code base.

There are also cases where final actions are performed in an old-fashioned C-style way by using goto statements (which is discouraged by C26438 NO_GOTO). It's hard to detect the exact intention in code that heavily uses goto, but some heuristics can help to find better candidates for cleanup.

Remarks

  • This rule is lightweight and uses label names to guess about opportunities to use final action objects.
  • Label names that can raise a warning contain words like "end", "final", "clean", and so on.
  • Warnings appear at the goto statements. You may see verbose output on some occasions, but the output may help in prioritizing code, depending on its complexity.
  • This rule always goes in pair with C26438 NO_GOTO. Depending on the priorities, one of these rules can be disabled.

Code analysis name: USE_GSL_FINALLY

Example

Cleanup with multiple goto statements:

void poll(connection_info info)
{
    connection c = {};
    if (!c.open(info))
        return;

    while (c.wait())
    {
        connection::header h{};
        connection::signature s{};
        if (!c.read_header(h))
            goto end;               // C26448 and C26438
        if (!c.read_signature(s))
            goto end;               // C26448 and C26438
        // ...
    }

end:
    c.close();
}

Cleanup with multiple goto statements replaced by gsl::finally:

void poll(connection_info info)
{
    connection c = {};
    if (!c.open(info))
        return;

    auto end = gsl::finally([&c] { c.close(); });
    while (c.wait())
    {
        connection::header h{};
        connection::signature s{};
        if (!c.read_header(h))
            return;
        if (!c.read_signature(s))
            return;
        // ...
    }
}