c++iteratorundefined-behaviordereference

Is it ok to write `&*string.end()`?


I see many places in public repositories, where the first and last iterators of std::vector/std::string/std::string_view are converted into pointers using the combination of &* operators. In particular, it is frequently used for calling std::from_chars, e.g.

auto const parse_int = [](std::string_view sv, int base = 10) -> int {
    int value;
    auto result = std::from_chars(&*sv.begin(), &*sv.end(), value, base);
    ...

Is it actually safe and not undefined behavior to dereference end() (which points on the element following the last element in the container/view) with * before converting it back to the pointer with &?

I tried to evaluate a similar code with &* in a constant expression, where undefined behavior must be detected by the compiler:

static_assert( [] {
    const char s[3] = { 'e', 'n', 'd' };
    [[maybe_unused]] auto * a = &*(s+3); // ok?
    [[maybe_unused]] auto & b =  *(s+3); // ok?
    return true;
}() );

But actually all compilers are fine with it, and do not complain, online demo.


Solution

  • No, its undefined behaviour, MSVC's debug iterators crash with the code: https://godbolt.org/z/K3a8YEYsr

    This is a known deficiency with std::from_chars, see: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2007r0.html

    The legal way to do it is with:

    std::from_chars(sv.data(), sv.data() + sv.length(), value, base);