6

I already heard that std::vector<T>::iterator can simply be T* instead of an iterator class.

But is it really legal?

Pointer arithmetic only applies to array and std::vector doesn't create array object (T[]) but contiguous objects (via placement new).

Moreover I think that std::launder would even be required (C++17) to access individual element (as we can read in comment of static_vector example of std::aligned_storage).

I think it is roughly equivalent to following that I think is undefined behavior.

template <typename T, std::size_t N, typename F>
void test_array(F func)
    typename std::aligned_storage<sizeof (T) * N, alignof (T)>::type data;
    char* buffer = &data;
    for (std::size_t i = 0; i != N; ++i) {
        new (buffer + i * sizeof(T)) T;
    }
    T* array = reinterpret_cast<T*>(buffer);
    for (std::size_t i = 0; i != N; ++i) {
        func(array[i]); // UB for (0 < i) ?
    }
    for (std::size_t i = 0; i != N; ++i) {
        array[i].~T();
    }
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • I'm pretty confident that actually most std implementations use raw pointers as iterators for `std::vector` – Sebastian Hoffmann Jul 09 '20 at 12:44
  • Both your points sound valid to me, so it would indeed be illegal. – HolyBlackCat Jul 09 '20 at 12:45
  • 2
    So basically, the vector problem and [P0593](http://wg21.link/p0593)? The mandate always was "this works because the standard says it works. And if an implementation makes it work like that, then it's fine". – StoryTeller - Unslander Monica Jul 09 '20 at 12:48
  • @SebastianHoffmann Do you mean under the hood, or that `std::vector::iterator` is an alias for `T *`? The latter is not the case at least for libstdc++, libc++, and MSVC's library. – HolyBlackCat Jul 09 '20 at 12:49
  • @HolyBlackCat Under the hood. I just verified, gcc just wraps it in a custom type for type traits but otherwise just forwards everything: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/bits/stl_iterator.h#L931 (`_Iterator` would e.g be `int*` for a `std::vector`). Good point though – Sebastian Hoffmann Jul 09 '20 at 12:53
  • Does the standard really "apply to itself"? I have doubts because it seems `memcpy` [can't be implemented legally](https://stackoverflow.com/questions/54336811/is-it-technically-impossible-to-implement-memcpy-from-scratch-in-standard-c), for example. (OK, that's C, but it illustrates my point). – alain Jul 09 '20 at 13:05
  • Much of the C++ standard library cannot be implemented in standard C++. `std::malloc` is my favourite. `memcpy` is indeed another one that can't be. – Bathsheba Jul 09 '20 at 13:06
  • Short answer: yes, it is legal. The requirements that `std::vector::iterator` are required to meet are summarised at https://en.cppreference.com/w/cpp/named_req/RandomAccessIterator If you check that, you'll see that a pointer can meet all requirements. Of course, types other than a pointer can ALSO meet the requirement. Not all implementations of the standard library use a pointer though, for various reasons (e.g. if an operation is performed on an iterator that is valid for a pointer, but not actually required on an iterator, such misuse is more likely to be diagnosed). – Peter Jul 09 '20 at 13:07

1 Answers1

5

std::vector::iterator is part of the Standard Library, and therefore part of the implementation. That means it may depend on implementation-specific details. In particular, the implementation may use pointer arithmetic in a non-portable way. If the implementation knows a T[] is indistinguishable from contiguously allocated T's, then it can do pointer arithmetic on them.

MSalters
  • 173,980
  • 10
  • 155
  • 350
  • So standard has right to write it as, in fact it is just *"internal"* implementation details (`` doesn't have to be a file, but just providing functions/class/include/... required (and *regular* C++ code is a convenient way)), whereas regular users wont be able to rewrite it that way. – Jarod42 Jul 09 '20 at 13:18
  • @Jarod42: The writes of the Standard are entirely aware that implementations may make different choices, and that `T*` is a valid choice. For some platforms, it could be beneficial so `std::vector::iterator` can be passed in a register. The Standard doesn't care. – MSalters Jul 09 '20 at 13:22
  • 1
    Sad that regular users cannot do the same and only compilers can do that. – Jarod42 Jul 09 '20 at 13:59
  • @Jarod42 - Compile as C++20. Vector is implementable – StoryTeller - Unslander Monica Jul 09 '20 at 15:00