My first guess is that it's undefined behavior, since you are trying to reference an element that has been erased. Edit: After more discussion, this appears to be wrong. See below.
Iterators, pointers and references pointing to position (or first) and beyond are invalidated, with all iterators, pointers and references to elements before position (or first) are guaranteed to keep referring to the same elements they were referring to before the call.
Looks okay to me. In the case of foo(), the return value ret is the wrapped reference to the element of the list l. The reference_wrapper has been erased, but the wrapped reference remains unaffected.
Guys, Just sorted this out. In short, it's just a vector question. In main(), since i was printing the v[0] value, I will see -3 as -4 has been popped off.
The interesting question, though, is instead of printing v[0], we print the list's first value (l.front() value). In this case, in foo(), ret will store the address of the first element of l, as reference can be generally treated as a constant pointer that implicitly dereferences itself. Then, even if we did v.erase(v.begin()), it only erased the first element of the reference_wrapper vector, not the actual list element. So ret in foo() still stores the right address to the first list element.
Guys, Just sorted this out. In short, it's just a vector question. In main(), since i was printing the v[0] value, I will see -3 as -4 has been popped off.
I'm pretty sure, as Ganado said, the behavior is undefined. Any container function that causes iterator invalidation leaves pointers and references into elements in an undefined state. There's no guarantee that the std::vector implementation works by shifting elements. For example, std::vector internally could just be an std::deque. In that case, on line 16 you would be accessing a destructed object.
on line 16 you would be accessing a destructed object.
Are you sure?
Vector v had an element erased. There were no pointers or references into v when the element was erased. Line 16 uses operator[] on the current value of vector v.
My understanding of the function foo (line 10) is that ret is assigned the value of v.front(). Because v is a std::vector of std::reference_wrapper<S> and ret is a S&, the contents of v.front() are cast to S&, and the vector element is no longer in play.
When the first element of v is erased, ret still contains a reference to the first element of l, which was not erased.
I haven't worked with reference_wrapper very much, so I may be missing some subtlties. Please correct me if I'm not reading this right.
The address of ret is the same as the address of the first element of the list, so I suppose it is just directly referencing the list element itself, regardless of what is erased from the vector. So I suppose it is safe.
In which case, the answer is the original question is straightforward: The first element of the vector was erased, so now the first element points to the -3 element.
That's what I get for not reading things properly. I would still not accept this code in a code review. It's too confusing. I'd rather see a vector of naked pointers.