From: Greg C. <chi...@co...> - 2007-01-29 14:59:36
|
On 2007-1-29 10:15 UTC, Chris Trobridge wrote: > Greg Chicares wrote: >> >> Wouldn't 'vec[vec.size()]' be undefined behavior and a likely >> reason for the program to crash? >> > I have only "C++ in a nutshell" to act as a reference. > > It states that the elements of the vector are stored contiguously in > memory, like an array, so at one level I don't think this is undefined > behaviour, assuming the book I have is correct. Valid subscripts run from 0 through size()-1 inclusive. 'vec[vec.size()]' attempts to return a reference to something outside the valid range, and that has undefined behavior. > I'd have thought that vec.end() would be more appropriate, but this is, > in effect, defined as &vec[vec.size()] anyway... 'vec.end()' and '&vec[vec.size()]' are not equivalent. 'vec.end()' is all right. It yields a one-past-the-end iterator. You can obtain such an iterator, and you can compare it to another iterator, but you mustn't dereference it. '&vec[vec.size()]' attempts to perform a dereference before it applies '&'. That's the difference. > So I would say end() is better as it avoids impression of accessing an > element outside of the vector. That's not just an impression: 'vec[vec.size()]' really does attempt to dereference something past the end, and its behavior is undefined. > The debug 'crash' is not entirely appropriate as there is no attempt to > access an element, merely to obtain the address past the end of the > vector, which is required for other stl operations. As I said, this is > exactly what end() does but more clearly and explicitly stated. It's undefined behavior, so it can crash. '&X[Y]' is not equivalent to 'X+Y'. The former means '&(*(X+Y))'. The compiler doesn't look at the '*' and '&' and cancel them against each other; instead, it attempts to perform them in sequence. (The C language was changed in 1999, so that the '&' and '*' do cancel; even if that rule is eventually embraced by C++, it'll apply only to arrays, not STL containers, because containers can overload subscripting.) > Finally while complains about the above, the debugger doesn't complain > about (&vec[0]+vec.size()], which is also equivalent. Again, what matters is whether it's dereferenced. > I think he should have used end() in the first place... > > The big puzzle is why the program ultimately ends the way it should? Because it's undefined behavior. UB is an important defined term, not a loose concept. One possible consequence of UB is a crash. > Surely an exception has been thrrown by the debug code but the > runtime/environment is catching this? Is there a particular compiler > setting to get exceptions reported properly? A segmentation violation is not a C++ exception. There's no compiler setting to trap segmentation violations. The compiler is performing properly. If you want bounds-checked access to a std::vector, with a C++ exception thrown if the bounds are violated, use at(). |