How to enable debug mode for C++ containers

The containers of the C++ standard library are incredibly useful to write compact code without having to reinvent basic data structures. Since the focus of C++ is always on performance, error checking is not performed in the use of these containers. For example, in a std::vector with 35 elements, you can access v[39] without C++ blinking an eye. You will of course get back invalid data that might silently poison the runtime execution of the program. std::vector offers a safer at(39) method that does the bounds checking, but it is slower and so not all code will use it. When a strange runtime error does occur in code using C++ containers, how to debug it?

If you are using GCC, thankfully it provides an alternate debug mode version of the C++ standard library where all the calls perform error checking. Finding your error becomes easier by using these debug mode C++ standard library containers.

Debug mode

You can change your entire C++ code to link with the debug C++ standard library by adding the -D_GLIBCXX_DEBUG compiler flag. This will replace all use of C++ standard library containers to their debug versions. On running the program, the container should report any error it finds.

However, this option may not be feasible if you are passing any C++ container in calls to external libraries (say OpenCV). Since these external libraries may not have been compiled with these flag, they cannot be linked. You will have to recompile all these external libraries with this flag to be able to link with them.

For example, my C++ code was calling some functions in OpenCV and passing a std::vector. On compiling with this debug flag, I got this error:

main.cpp.o: In function `main':
main.cpp:92: undefined reference to `cv::imwrite(std::string const&, cv::_InputArray const&, std::__debug::vector<int, std::allocator > const&)'
error: ld returned 1 exit status

The error is indicating that it cannot find a OpenCV function definition that takes a std::__debug::vector as input.

Debug container

If you are stuck with the above scenario where you use an external library that is not compiled in this debug mode, there is an alternative. Find the definitions of containers in your code that are suspect and only change those specifically to the debug version of the container.

For example, I suspected a certain std::vector in my code, so I changed its definition to:

#include <debug/vector>

// Earlier this was:
// std::vector<int> pick_vec;
// Changed now to:
std::__gnu_debug::vector<int> pick_vec;

On compiling and running this code, the out-of-bounds error was found by the debug container:

/usr/include/c++/4.9/debug/vector:357:error: attempt to subscript container 
    with out-of-bounds index 39, but container only holds 35 elements.

Objects involved in the operation:
sequence "this" @ 0x0x7ffffc4d5fe0 {
  type = NSt7__debug6vectorIN2cv7Point3_IfEESaIS3_EEE;
}

The list of C++ debug containers and their header files can be found listed here.

Tried with: GCC 4.9 and Ubuntu 14.04

How to use emplace operations of C++11

C++11 introduced emplace operations on many of the STL containers. For example, vector now has emplace_back operation along with the old push_back operation.

Emplace operation is provided for convenience, to make writing code in C++ a bit more easier. It should be used when you want to add an object by constructing at the point of calling the emplace operation. For example, you may want to construct the object using its default constructor and then push it into the container. Or you may want to construct it using some parameters on the spot. The older alternative for this involved the construction of a temporary object and then copying it into the container.

The code below shows a simple example of these scenarios:

C++: Empty a vector for real

clear() is the method used to empty a STL vector in C++. However, it merely sets the size of the vector to zero. In almost all STL implementations, the vector is still consuming the same amount of memory it was before the call to clear(). This can be seen by calling the capacity() method, which returns the actual number of items which the vector can hold without needing or reallocating any new memory.

#include <iostream>
#include <vector>
int main()
{
    vector< int > v( 1000000 );
    v.clear();
    std::cout << v.capacity() << std::endl; // 1000000
    return 0;
}

But, there will be situations where memory is tight and you would like to actually clear a vector of all its memory. This can be achieved using the shrink_to_fit() method, which was introduced in C++11:

v.clear();
v.shrink_to_fit(); // Capacity of v is now 0

If you are using an old C++ compiler or STL implementation that does not support shrink_to_fit(), there is another trick to empty a vector: swap its contents with a vector that is actually empty:

vector< int >().swap( v ); // Capacity of v is now 0

Our original vector now points to the (empty) space of the new vector. The new vector now points to the capacity of the old vector. But, the lifetime of the new vector is the scope of this statement. As soon as that scope ends, the new vector is deleted, thus freeing the memory occupied by the old vector.

Tried with: Visual C++ 2010