How to Make Std::Vector's Operator[] Compile Doing Bounds Checking in Debug But Not in Release

How to make std::vector's operator[] compile doing bounds checking in DEBUG but not in RELEASE

Visual Studio 2005 and 2008 already do bounds-checking on operator[] by default, in both debug and release builds.

The macro to control this behavior is _SECURE_SCL. Set it to 0 to disable bounds-checking.

Their current plan in VS2010 is to disable bounds-checking by default in release builds, but keep it on in debug. (The macro is also getting renamed to _ITERATOR_DEBUG_LEVEL. I don't know if there's any formal documentation available on it yet, but it has been mentioned here and here)

Automatically check bounds in std::vector


To me, this utility template seems to be so straight-forward that I'd
expect it to exist

For gcc it does exist. gcc libstdc++ has a set of debug containers. For std::vector it has __gnu_debug::vector debug container. See documentation.

Convert between vector::operator[] and vector::at in C++


Like

If (DEBUG)
{
// Do with .at
}
else
{
// Do with []
}

You get something like this by using operator[] and by enabling bounds checking debug mode of the standard library implementation that you use. How to do that, and whether that option exists depends on what implementation you use.

Note that typically the entire project, including all libraries must have been built with the same standard library options. This is a potential problem if you use pre-built libraries.

A universally portable solution is to write a wrapper function that conditionally calls one function or the other depending on build configuration. Downside is that this requires changing all code using the wrapped function to use the custom one.

Why std::vector::at() needs bounds checking even with optimizations turned on?

The C++ standard requires bounds checking for at() and the actual implementation code for at() does contain the bounds checking.

In your first case however, the bounds are hardcoded (10 elements vs. index 3) and "everything" gets inlined with -O2, so the optimizer of the compiler removes the code for the bounds-check violation, because it can prove at compile time that the bounds are not violated and the code path not taken (as-if rule).

Therefore, you don't get a linker error with -O2 in that case, because the compiler simply didn't emit the call instruction at all.


Shouldn't -O2 completely eliminate bounds checking?

No, the optimizer has to keep to the AS-IF rule, that is, iff the optimizer can prove, at compile time, that a code path is not taken, it can eliminate that code. It doesn't just willy-nilly remove checks that were introduced in the source code.

As a side note, for vector::operator[] that doesn't require bounds checking, an implementation could (reasonably or not) introduce debug bounds checking, when e.g. NDEBUG is not defined, and only do no checking when NDEBUG is defined. In that case however, the bounds check would be "removed by the preprocessor" if you will, and not by the optimizer.

How to switch from vector::at() to [] when building Release

If you want no bounds checking overhead at runtime, then use the subscript operator.

With most standard library implementations, you can enable non-standard bounds checking in subscript operator. Usually by defining a macro. This has a caveat, that the entire program must be compiled in the same mode, including any linked libraries.

Address/UB sanitisers should also be used when testing and debugging, and they may also detect typical buffer overflow conditions in absence of standard library support.

Is it possible to compile so that erroneous std::vector access calls will exit the program, and with a helpful error message?

Compile with -D_GLIBCXX_DEBUG to enable debug mode in STL containers.

Alternatively you can also use specific debug containers which live in the __gnu_debug namespace, e.g. __gnu_debug::vector:

#include <iostream>
#include <debug/vector>

int main()
{
__gnu_debug::vector <int> x(1);
for(int q = 0; ; q++)
{
int y = x[q];
std::cout << q << " ";
}
}

C++ replacement: Replacing every occurence of v[x] with v.at(x)

You may consider overloading the method in a new inheritance, as follows

#include <iostream>
#include <vector>

template< class T, class allocator = std::allocator<T>>
struct Vector : std::vector<T, allocator>{
using std::vector<T, allocator>::vector;

const T& operator[](size_t i)const{
return this -> at(i);
}

T& operator[](size_t i){
return this -> at(i);
}
};

template< class T>
Vector(size_t, T ) -> Vector<T>;//if u want to use c++17 deduction guides

int main()
{
std::vector<int> vec1(4,1);
std::cout << vec1[4];

Vector vec2(4,1);
std::cout << vec2[4];

}

Compile time triggered range check for std::vector

If I'm not mistaken, this is the usual situation with Visual Studio. With g++, you have to invoke the compiler with -D_GLIBCXX_CONCEPT_CHECKS -D_GLIBCXX_DEBUG -D_GLIBCXX_DEBUG_PEDANTIC. (It's probable that you don't need all three, but I use all
three systematically.) With other compilers, check the documentation. The purpose of the undefined behavior in the standard here is precisely to allow this sort of thing.



Related Topics



Leave a reply



Submit