References, pointers, const, and lifetimes
Borrowed views, aliases, nullable observers and dangling
A reference is an alias to an existing object; binding one does not create a new owner or extend every possible lifetime. A pointer can be null and reseated. Neither a raw pointer nor a span automatically keeps its target alive. const T* prevents mutation through that pointer; it does not promise some other alias cannot mutate the same object.
std::vector<Int> values{4,5,6};
std::span<const Int> view(values);
const Int* observer=&values[1];
values[1]=9; // observer and view now observe 9Int* const is a fixed pointer to mutable Int; const Int* is a mutable pointer to const-accessed Int. Top-level const on a copied parameter does not constrain a caller's object. Const correctness describes access paths, not ownership. A function returning a pointer or view must state whose storage it borrows and what invalidates that storage.
// Dangling: returns a view into a vector destroyed on return.
// std::span<const Int> wrong() { std::vector<Int> v{1}; return v; }Returning a span into the original input permits zero-copy slices, but transfers lifetime obligations to the caller. Vector reallocation, erasure of covered elements, or destruction invalidates the result. Passing a temporary vector to a borrowing API can therefore produce a dangling result after the full expression. A copy would be safer for long-lived independent data; a view is useful when the caller controls a clear enclosing lifetime.
The exercises check addresses and aliasing while owners are still alive. They deliberately never dereference a dangling pointer: undefined behavior is not a reliable test assertion. Empty spans need special care because their data pointer may be null, so avoid blindly forming pointer arithmetic on it.
Put it into practice
Implement the exercise in a full-screen workspace, then run its tests.