I think this is a problem worth solving.  Its against a C++ design principle that built-in references (like const std;:string&) have the lifetime extension feature, whereas user-defined reference-like classes (like std::string_view) do not.  In particular, this is one the arguments against migrating from const std::string& to std::string_view.

I encourage you to submit a proposal for C++23: https://isocpp.org/std/submit-a-proposal

On Thu, Dec 19, 2019 at 8:44 AM Martin Küttler via Std-Proposals <std-proposals@lists.isocpp.org> wrote:

Hi,

first, merry Christmas to all who care. To the rest, merry next week.

Secondly, I'd like to propose an attribute view (or called
differently). This is my first attempt to advertise this, so feel free
to redirect me. I understand that visiting a meeting is recommended
before such a proposal. Unfortunately, my health does not allow me to do
so.

One of the main issues of std::string_view is ilustrated by the
following example.

std::string const hello = "hello";
std::string_view s = hello + ", world";
// access of s is UB

Interestingly, this problem does not occur in the following code.

std::string const hello = "hello";
std::string const & s = hello + ", world";
// access of s is fine

Intuitively, this should result in the same problem: a reference to a
temporary is taken. But in [class.temporary] it is specified that
``when a reference is bound to a temporary object [...] the
temporary object that is the complete object of a subobject to which
the reference is bound persists for the lifetime of the reference
if [...].'' This does not apply if the temporary is bound to a T
const & argument of a constructor. The presence of such an argument
does not imply the need for this mechanism, as the argument might be
used to copy a subobject, call const member functions, or might be
discarded.

The proposed solution is to add a new attribute, called view in the
following, to the argument, that indicates that the extension of the
lifetime is desired. The attribute is needed in the declaration (as it
changes behaviour at the call site). Requiring consistancy between all
declarations and the declarations and the definition is optional, but
assumed here. Adding this attribute has two positive effects at the
call site:

 - The lifetime of temporaries can be increased appropreately. This
   reduces the occurance of dangling references.

 - A diagnostic message can be issued if the compiler can not
   defer the destruction of the temporary long enough, e.g. when an
   object constructed with a temporary bound to a view argument is
   returned.

The second point makes this an interesting feature to allow for T&, T*
and T const * as well.

In the definition diagnostics indicating the need of an added view
are possible. This is the case e.g. if a reference to a subobject of
an argument is stored in a constructor, or if an owner pointer is
copied. This is not completely investigated yet, but additional
diagnostics can be added later.

The motivation for allowing view arguments in other functions but
constructors is twofold.

 - Starting in C++20, a function might be a coroutine, outliving
   the point it is called from. According lifetime is required from its
   arguments.

 - An argument to a normal function might be used to construct an
   object that outlives the function, e.g. by being returned. In this
   case, the arguments should be marked view recursively. Technically
   speaking this case probably includes the coroutine-case. Diagnostic
   messages for arguments used to construct view parameters to other
   calls, that are not themselves marked view, should be required.

Implications for old code
-------------------------

Code that does not use the attribute view is not impeded. Additional
diagnostics might ensue, but no behavioral change is required from
this code.

Usages in the standard library
------------------------------

The attribute should be added to all views (std::string_view, std::span
and some in std::ranges::views, I think) to the constructors taking a
std::string const & or a char const* in the first case, and a
std::array<T, n> const & or a T (&)[n] in the second case. std::span has
a hand full of constructors, some of which need the attribute as
well. In addition the copy constructors of both classes need the
attribute. The same probably holds for many constructors of most of the
classes in std::ranges::views, but I'm no expert there.

Conditional view
----------------

To accommodate "view-correct" template code, a form of conditional
view-ness is needed. This requires a syntax to request the presence of
the argument at the n-th parameter of a specific function. I do not yet
have decided how that should look.

Regards,
Martin Küttler
--
Std-Proposals mailing list
Std-Proposals@lists.isocpp.org
https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals