Why is undefined behavior allowed in the STL?

c++, stl, undefined-behavior

Solution

When undefined behaviour is allowed, it's usually for reasons of efficiency.

If the standard specified what has to happen when you access an array out of bounds, it would force the implementation to check whether the index is in bounds. Same goes for a vector, which is just a wrapper for a dynamic array.

In other cases the behaviour is allowed to be undefined in order to allow freedom in the implementation. But that, too, is really about efficiency (as some possible implementation strategies could be more efficient on some machines than on others, and C++ leaves it up to the implementer to pick the most efficient strategy, if they so desire.)

Problem

By default, the "underlying container" of an `std::stack` is an `std::deque`. Therefore anything that is undefined behavior for a `std::deque` is undefined behavior for a `std::stack`. cppreference and other sites use the terminology "effectively" when describing the behavior of member functions. I take this to mean that it is for all intents and purposes. So therefore, calling `top()` and `pop()` is equivalent to calling `back()` and `pop_back()`, and calling these on an empty container is undefined behavior. From my understanding, the reason why it's undefined behavior is to preserve the no-throw guarantee. My reasoning is that `operator[]` for `std::vector` has a no-throw guarantee and is undefined behavior if container size is greater than N, but `at()` has a strong guarantee, and throws `std::out_of_range` if n is out of bounds. So my question is, what is the rationale behind some things having possibly undefined behavior and having a no throw guarantee versus having a strong guarantee but throwing an exception instead?

Original source