Warning C26449

gsl::span or std::string_view created from a temporary will be invalid when the temporary is invalidated (gsl.view)

C++ Core Guidelines: GSL.view: Views.

Spans and views are convenient and lightweight types that allow you to reference memory buffers. But they must be used carefully: while their interface looks similar to standard containers, their behavior is more like the behavior of pointers and references. They don't own data and must never be constructed from temporary buffers. This check focuses on cases where source data is temporary, while a span or view isn't. This rule can help to avoid subtle but dangerous mistakes made when legacy code gets modernized and adopts spans or views. There's another check that handles a slightly different scenario involving span references: C26445 NO_SPAN_REF.

Consider using C26815 and C26816. Those warnings are more general versions of this warning.

Remarks

  • This rule warns on places where constructors get invoked for spans or views and the source data buffer belongs to a temporary object created in the same statement. This check includes:

    • implicit conversions in return statements;
    • implicit conversions in ternary operators;
    • explicit conversions in static_cast expressions;
    • function calls that return containers by value.
  • Temporaries created for function call arguments aren't flagged. It's safe to pass spans from such temporaries if target functions don't retain data pointers in external variables.

  • If spans or views are themselves temporaries, the rule skips them.

  • Data tracking in the checker has certain limitations; therefore complex scenarios involving multiple or obscure reassignments may not be handled.

Code analysis name: NO_SPAN_FROM_TEMPORARY

Example

Subtle difference in result types:

// Returns a predefined collection. Keeps data alive.
gsl::span<const sequence_item> get_seed_sequence() noexcept;

// Returns a generated collection. Doesn't own new data.
std::vector<sequence_item> get_next_sequence(gsl::span<const sequence_item>);

void run_batch()
{
    auto sequence = get_seed_sequence();
    while (send(sequence))
    {
        sequence = get_next_sequence(sequence); // C26449
        // ...
    }
}

To fix the issue, make sure the view is created from an object that lives at least as long as the view itself. Sometimes a solution can be achieved by copying the data, other times some APIs need to be redesigned to share a reference to an object that lives long enough instead of returning a temporary copy.

See also

C26815
C26816