Visual Studio Debug Iterators

Visual Studio debug iterators

Stephan Lavavej has provided some detail on this _SECURE_SCL and _HAS_ITERATOR_DEBUGGING:

From http://blogs.msdn.com/b/vcblog/archive/2007/08/10/the-future-of-the-c-language.aspx

Iterator debugging, enabled by
_HAS_ITERATOR_DEBUGGING, performs powerful correctness verification.
Iterator checking, enabled by
_SECURE_SCL, performs minimal checks that serve as a last line of security
defense. For example, _SECURE_SCL
will terminate a program that triggers
a heap overrun with a vector iterator.

All that is explained by MSDN
documentation. The story behind this
is interesting. The
_HAS_ITERATOR_DEBUGGING functionality was provided by Dinkumware, the
company that licenses their most
triumphant implementation of the
Standard Library for inclusion in
Visual Studio. The _SECURE_SCL
functionality was added by Microsoft,
in order to improve the security of
programs running on Windows. In order
to perform their checks, both
_HAS_ITERATOR_DEBUGGING and _SECURE_SCL make iterators contain additional data members, such as
pointers to their parent containers.
_HAS_ITERATOR_DEBUGGING, because it is enabled by default in debug mode (and
not obtainable in release mode), also
builds singly linked lists that allow
containers to refer to all of their
iterators. This is expensive
performance-wise, but performance is
not critical in debug mode, and this
enables excellent checks.

_SECURE_SCL, because it is enabled by default in release mode, strives to
impose minimal performance penalties.
Therefore, when it is enabled,
although iterators have pointers back
to their containers, containers don't
have pointers to their iterators.
(Updating "iterator lists" is too
time-consuming for release mode.)

Note that starting in VS 2010, _SECURE_SCL is no longer enabled by default in release mode (the above excerpt is from 2007).

As described in this bug report (http://connect.microsoft.com/VisualStudio/feedback/details/334315/has-iterator-debugging-0-causes-crash), both _SECURE_SCL and _HAS_ITERATOR_DEBUGGING affect the ABI:

_SECURE_SCL and _HAS_ITERATOR_DEBUGGING significantly change the behavior and
representations of STL containers and
iterators. VC9 (Visual Studio 2008)
made the representations of STL
containers and iterators even more
strongly dependent on _SECURE_SCL and
_HAS_ITERATOR_DEBUGGING (this was done to fix a conformance bug).

Because these macros change the
representations of STL objects, you
must observe certain rules when
changing these macros from their
defaults. I described the rules here:
http://blogs.msdn.com/vcblog/archive/2007/08/10/the-future-of-the-c-language.aspx#4617984 To summarize, the macros must be
consistent within each binary (EXE or
DLL), and furthermore, binaries that
pass STL objects to each other must
have consistent macro settings. Your
example involves an EXE and DLL
passing a vector between
themselves, so the EXE and DLL need to
have the same _SECURE_SCL and
_HAS_ITERATOR_DEBUGGING settings.

These rules apply to VC8, VC9, and all
future versions. Your code happened to
work with VC8 (Visual Studio 2005),
but would fail if it did more
complicated things.

C++ Debug Assertion Failed; Expression: list iterators incompatible

The code is comparing incompatible iterators. It is illegal to compare two iterators that come from different container instances. The standard says: The domain of == for forward iterators is that of iterators over the same underlying sequence.

This requirement is not satisfied by the code, where it may iterate over one std::unordered_map<int, double>, and adj_list[track.top()] may be another std::unordered_map<int, double> object. This incompatibility is caused by the changing of the value of track.top(), due to the line:

            track.push(it->first);//  <--When I comment out this line, the code runs.

When not running under debug mode, the code may suddenly start running, since the compiler no longer generates this validation code, but it also may trash your memory and crash in weird ways.

The error is quite clear: the code compares iterators that come from different container objects. The iterators must come from the same container object.

What factors make iterators so slow in debug mode (VC++ 2012)

Bounds checking aside, debug builds of STL code produces an insane amount of function calls.
Some innocent lines like:

if (a.empty())

can produce as much as 8 (or more) function calls.
Some (all?) STL implementations are not optimized for debug builds at all.

A common performance issue with STL is that devs think that function inlining always works. It doesn't. If too many inline functions are called the bottom ones do not get inlined and you have a massive performance hit just by the function calls overhead.
This is very common when having containers of containers:

map< string, map< int, string>>

operations on the outer map can cause inline functions to stay as normal functions.

visual studio 2013 debug iterator container

As Praetorian mentioned, in VS you can enumerate the values of the pointer to see the contents of the container your iterator is iterating over.

A watch variable like:

(MyIterator)._Ptr, 5

or

(MyIterator)._Ptr, NumElements

will enumerate the first NumElements elements in the container.

How to get the element value of the iterator in Visual Studio immediate window ? *iterator doesn't work

The * operator is overloaded for iterators in order to give you access to their underlying value, and keep the same semantics as pointers. Pointers can be considered, in some context, as iterators, for example when iterating over a C-style array. That's why you can use C- style arrays in STL algorithms.

The immediate window in visual studio seems to not understand that the * operator is overloaded for your iterator type. That's why you get this error.

Debug assertion failed visual studio 2015: vector iterator not dereferencable

while (((*it).price <= newEl.price) && (it < v.end())) {

You need to check if you are at the end before you dereference the iterator and check the value:

while ( (it!=v.end()) && (it->price <= newEl.price)) {

Otherwise you are basically guaranteeing you will dereference the end iterator, which is precisely what you are trying to avoid.

(You can't use < on most types of iterator, so checking the loop with != is a more common practice).

You may be aware that && "short-circuits" so, if the first condition is false, the second one doesn't even get checked. This is guaranteed by the language (unless some idiot overloads operator&&, but that is thankfully rare, because it is such a bad idea). That is why my version is safe.

Now, this mistake triggers Undefined Behaviour - the error is on you! The language doesn't even try to help you, and anything can happen. Your program could crash, it could appear to work normally, it could work every other time, or it could turn your laptop into a pink giraffe. C++ trades being nice to you against being fast.

I know the Microsoft implementation, in debug mode, has checked iterators which are catching your mistake here, at the cost of always checking. In release mode this wouldn't happen.

I've not used it, but according to this answer, GCC does have something similar.


(As an aside, I really consider use of std::endl to be bad practice. Here's why. Some people do disagree with me on that. Learn about it and make your own decision, I suppose.)

Debug Assertion : Vector iterators incompatible (C++)

You have not posted enough code to be really sure, but the following guess should be correct:

getElements() most likely returns by value, not by reference.

For example:

std::vector<std::shared_ptr<GameGridElement>> Field::getElements()
{
// ...
return result;
}

This returns a copy! Which means that every time you call getElements, you get a different vector.

For the compiler, this does not make any difference. Type safety does not help you, because a std::vector<std::shared_ptr<GameGridElement>>::iterator is a std::vector<std::shared_ptr<GameGridElement>>::iterator, even if you have two iterators which belong to different container instances. They have the same type, so the code compiles.

At run time, however, additional checks can be made to ensure that two iterators that are being compared really belong to the same container object. This turns seemingly random "strange" behaviour or spurious crashes into a definite guaranteed crash to immediately tell you that something must be fixed.

Consider again this line:

for (
std::vector<std::shared_ptr<GameGridElement>>::iterator
it = m_pGameField->getField(i, j)->getElements().begin();
it != m_pGameField->getField(i, j)->getElements().end();
++it
)

it is initialised to getElements().begin() and is then compared by != to getElements().end(). But as explained above, each getElements() returns a different vector, so you get incompatible iterators.

Here is an easy way to solve the problem:

std::vector<std::shared_ptr<GameGridElement>> elements =
m_pGameField->getField(i, j)->getElements();

for (std::vector<std::shared_ptr<GameGridElement>>::iterator it = elements.begin();
it != elements.end(); ++it)

This makes sure that begin() and end() return iterators to the same container instance.


For reference, here is a simple piece of code to reproduce the behaviour:

#include <vector>

int main()
{
std::vector<int> v1;
std::vector<int> v2;

bool b = v1.begin() == v2.begin();
}

Note that the C++ standard does not mandate iterator-compatibility checks at run time. Your compiler has to offer them and you must use the correct compiler options to enable them, or disable them if you don't need them or cannot afford them.


By the way, if you can use C++11, then you can use a range-based for loop to not only fix the bug but also make the code a lot more concise.



Related Topics



Leave a reply



Submit