2

I'm wondering if this is defined:

vector<int> v;
v.push_back(1337);
int * p1 = &*vi.end();

(Update 1 If this is undefined, I'd like to know more about exactly where my error is. For example, perhaps the reference int &r = &*(v.data()+v.size()) is legal in general, but *end() isn't required to return that. )

(Update 2 I'm really just curious about the pedantic language-lawyer question as to what can be defined. I have no difficulty coding uncontroversial workarounds :-) )

Anyway, of course, using an end-iterator like this looks bad. But first, consider this:

int array[3];
int * p2 = array + 3;

Clearly p2 is defined.

The, according to this answer, p2 is equivalent to p3 in this code: (if you're using C99):

int array[3];
int * p2 = array + 3;
int * p3 = &array[3]; // looks bad, but OK in C99

(I'm more curious about C++ though, and a comment to that answer implies that C++ allows it also. So, the above C99-compatible code is defined in C++.)

Moving closer to C++, I think I can write this:

int & r1 = *p3;

I agree that r1 looks really bad. And certainly, it would be UB if we did something like int x= r1;. That is UB because it involves an lvalue-to-rvalue conversion. But can we say that r1 is still just an lvalue? And therefore we can take its address?

int * p3 = &r1;

If all this is valid, then we can argue that a one-past-the-end reference is generally valid - for C-arrays at least. So, what can we say about *v.end()?

The operator*() method returns an int& reference. Does the standard require that it return one of these one-past-the-end references that we are allowed to take the address of?

Bonus: what if the vector is empty? In particular, is (&*v.end())==(&*v.begin())

Community
  • 1
  • 1
Aaron McDaid
  • 26,501
  • 9
  • 66
  • 88
  • 1
    *Dereferencing* the address one past the end of the allotted memory is undefined behavior. Taking the address is fine. – David G Apr 13 '15 at 16:55
  • You should consider dereferencing any interator pointing to non existing elements (even when implemented as pointer) as undefined behavior. –  Apr 13 '15 at 17:04
  • @0x499602D2, I'll see if I can remove the word 'dereference' from my question. It doesn't help – Aaron McDaid Apr 13 '15 at 17:45

2 Answers2

4

No, any * on v.end() is illegal.

You can do v.data()+v.size() instead for a pointer to the end, and v.data() for a pointer to the beginning.

This is defined even for an empty std::vector.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • `.data()` is only in C++11, any pre-C++11 solution? – Aaron McDaid Apr 13 '15 at 17:44
  • @AaronMcDaid Write a free `data` function: `template T* data( std::vector& v ) {if (v.empty()) return 0; return &v[0]; } template T const* data( std::vector const& v ) {if (v.empty()) return 0; return &v[0]; }` Now you can `data(v)` and `data(v)+v.size()`. Of course, this runs into `operator&` overloading issues, which you'd fix with `std::addressof`, which is C++11 as well. ;) – Yakk - Adam Nevraumont Apr 13 '15 at 17:45
  • @AaronMcDaid The first std::vector specification has data as member! –  Apr 13 '15 at 17:57
  • @Yakk I am pretty sure (I guess even the HP implementation has it) –  Apr 13 '15 at 18:04
  • @Yakk BTW: I am the opposite of being fat –  Apr 13 '15 at 18:25
  • A re-C++11 solution might look like this: v.size()?&v[0]+v.size():0 – Meixner Apr 14 '15 at 08:06
-1

v.end() points one beyond the last element. Therefore, dereferencing it is illegal.

You could use *(v.end()-1) to get the last element as long as v.size()>=1.

(Or use &*(v.end()-1) to get a pointer to it.)

Meixner
  • 615
  • 5
  • 8