2

Is this undefined behavior?

ptrdiff_t one() {
   std::vector<int> test(1);
   return &test[1] - &test[0];
}

Is this undefined behavior?

ptrdiff_t zero() {
   std::vector<int> test;
   int * end = &test[0];
   int * begin = &test[0];
   return end - begin;
}

If either of these are undefined behavior, can anyone help me locate the section in the C++11 spec where it describes that the subscript operator of a vector must be called on a value less than (rather than less than or equal to) size, or vice versa?

Thanks

Praetorian
  • 106,671
  • 19
  • 240
  • 328
hellcatv
  • 573
  • 4
  • 21
  • I found that for valarray "6 If the subscript operator is invoked with a size_t argument whose value is not less than the length of the array, the behavior is undefined." in 26.6.2.4 -- I'm curious why that kind of clarity doesn't exist for vector. I definitely searched for a while and found a lot of related questions, but not about this particular nuance: and I think if it's not undefined behavior that it's new for C++11. – hellcatv Nov 21 '14 at 20:11
  • @sehe: `std::vector` != C-style array. – Xeo Nov 21 '14 at 20:15
  • @Xeo I'm aware of that. I'd have removed that - but somehow that comment was not shown on my browser. (I probably back-buttoned it) – sehe Nov 21 '14 at 20:16
  • @hellcatv: `valarray` is not defined with the _containers_, whose definitions are stated rather more nebulously. – Lightness Races in Orbit Nov 21 '14 at 20:24
  • I've found [the real dupe](http://stackoverflow.com/q/17731133/560648). – Lightness Races in Orbit Nov 21 '14 at 20:33
  • 1
    The solution to your problem is `&vec.data()[0]` and `&vec.data()[1]` I think -- or just `vec.data()` and `vec.data()+1` even better. The rules barring dereferencing of an iterator don't apply to pointers, and in general if you want to access the "raw pointers" to the data in a vector, use `data()`. This even handles the empty vector case. – Yakk - Adam Nevraumont Nov 21 '14 at 21:32
  • As for "finding the real dupe"...you found a different question that had the same answer. Actually dereferencing the item off the end of the vector and assigning to it is a lot less common an idiom than someone who wants to just do pointer math on the resulting &myvector[myvector.size()] - &myvector[0] (which usually works in practice, despite being undefined behavior--so this would be news to those folks). Also the 'duplicate' poster chose an example where the item was 2 out of range...and C allows Carray address calculation at exactly the end explicitly for pointer math. – hellcatv Nov 25 '14 at 08:34

1 Answers1

6

Yes, those program fragments have undefined behaviour.

Table 101 defines test[0] as *(test.begin() + 0), which is invalid if you have no elements:

[C++11: 24.2.1/5]: Just as a regular pointer to an array guarantees that there is a pointer value pointing past the last element of the array, so for any iterator type there is an iterator value that points past the last element of a corresponding sequence. These values are called past-the-end values. Values of an iterator i for which the expression *i is defined are called dereferenceable. The library never assumes that past-the-end values are dereferenceable. [..]

Table 106 states dereferenceability as a pre-requisite for the validity of *i, given any iterator i.

It doesn't matter that you try to take the address afterwards: you've already broken your program. For example, your standard library implementation may compliantly trigger an assertion from operator* for any past-the-end iterator.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055