Search code examples
c++stlassert

Why do STL implementations not use assertions to detect undefined behaviour?


This is something that I feel could come in useful but that I have not seen implemented in gcc's standard library.

Basically, it would seem to me that STL implementations could add assertions to detect (at runtime) simple errors like out-of-bound access. I'm guessing that these accesses are undefined behaviour in the standard anyhow, so surely printing an error message and -optionally- aborting would be standard compliant.

These assertions could of course be turned off at compile time through the old NDEBUG flag or some other flag.

As a small example, I would like this code to abort:

#include <vector>

int main()
{
    return std::vector<int>{1,2}[2];
}

By the way, I am fully aware of the existence of tools like valgrind, but this could be a bonus. Also a memory checking tool like valgrind is not guaranteed to detect certain errors like access to an out-of-bounds element after a vector has been shrunk in size, since the implementation might not reallocate the underlying memory immediately.


Solution

  • This is something that I feel could come in useful but that I have not seen implemented in gcc's standard library.

    You're wrong, try defining _GLIBCXX_DEBUG, which makes your example abort:

    /home/jwakely/gcc/5/include/c++/5.0.0/debug/vector:402:error: attempt to 
        subscript container with out-of-bounds index 2, but container only 
        holds 2 elements.
    
    Objects involved in the operation:
    sequence "this" @ 0x0x7fffb8b221a0 {
      type = NSt7__debug6vectorIiSaIiEEE;
    }
    Aborted (core dumped)
    

    These assertions could of course be turned off at compile time through the old NDEBUG flag or some other flag.

    The reason this uses a separate mechanism and not assert() and NDEBUG is because the checking adds overhead, so it is only enabled when explicitly requested. This means that users can continue to use assert() for their own checks without turning on the overhead of the standard library checking. There are also binary compatibility issues to be aware of with libstdc++'s debug mode, due to additional data members used to track iterator validity. See https://gcc.gnu.org/onlinedocs/libstdc++/manual/debug_mode.html for details.

    Libc++ has similar checks as well, using a different macro, and VC++ enables similar checks automatically in debug builds.