Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Assigning value of unassigned iterator

28 views
Skip to first unread message

backminator

unread,
Aug 24, 2010, 5:00:22 PM8/24/10
to
Hi all.

I've been running c++ code under Linux gcc 2.93->4.4.3, OSX, and
Windows (VisualStudio 2005-2008) for > 3 years.
Now we are upgrading to VS2010 which supports C++00. We now suddenly
got a problem related to iterators.
The question is really, is the code below valid or not? It runs ok on
every instance of a compiler I can get my hands on, except VS2010.

It crasches on the assignment of the iterator, where it is trying to
dereference a null pointer.
My question is not really about this and that implementation of
compiler, its more of a C++, is this ok question.
Using unassigned iterators is not valid. The question is what the
below example shows?

It is a snippet from a larger code, where we have a container
containing a pair, containing an iterator.
So something like: std::vector<std::pair<int,
std::list<int>::iterator> >

So at any point, where you happens to assign a valid iterator the
value of an unassigned one, it crasches in VisualStudio 2010.
We might be able to refactor all the code having iterators in the
default constructor of the class, but Im not sure we want to ;-)

#include <list>
int main()
{
typedef std::list< int > IntList;

IntList integerList;
typedef IntList::iterator IntIterator;

IntIterator it1 = hej.end();
IntIterator it2;

it1 = it2;
return 0;
}

More elaborated example that show why we need this to work (and it
does in all C++ compilers except VS2010).

#include <list>
int main() {
typedef std::list< int > IntList;
typedef IntList::iterator IntIterator;

IntList integerList;

struct A
{
IntIterator it;
};

A a, b;
a.it = integerList.end();

a = b; // << here it crasches due to the test:
_Adopt(_Right._Myproxy->_Mycont); in xutility (STL)

return 0;
}

/Anders

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

slobasso

unread,
Aug 24, 2010, 8:05:35 PM8/24/10
to
On Aug 24, 2:00 pm, backminator <backmina...@gmail.com> wrote:
> IntIterator it2;
>
> it1 = it2; // <- this will result in undefined behavior

For most iterator types a default constructed iterator is not a valid
source for assignment. It is rare to find an implementation for which
this will actually crash, but it is possible and well within the
implementers right to do so.

Also realize that default constructed iterators or iterators from
different containers are technically not comparable to each other. So
at some point your code really needs to know what the state of these
iterators are.

Using a good debug implementation will usually find these kinds of
issues.

The standard can be a bit difficult to read so I suggest this:
http://www.sgi.com/tech/stl/trivial.html

It is best to avoid undefined behavior whenever possible even when it
doesn't cause a crash.

Kai-Uwe Bux

unread,
Aug 24, 2010, 8:04:25 PM8/24/10
to
backminator wrote:

> Hi all.
>
> I've been running c++ code under Linux gcc 2.93->4.4.3, OSX, and
> Windows (VisualStudio 2005-2008) for > 3 years.
> Now we are upgrading to VS2010 which supports C++00. We now suddenly
> got a problem related to iterators.
> The question is really, is the code below valid or not? It runs ok on
> every instance of a compiler I can get my hands on, except VS2010.

[...]


>
> #include <list>
> int main()
> {
> typedef std::list< int > IntList;
>
> IntList integerList;
> typedef IntList::iterator IntIterator;
>
> IntIterator it1 = hej.end();
> IntIterator it2;
>
> it1 = it2;
> return 0;
> }

I think, it's undefined behavior. std::list< int >::iterator has a default
constructor, but as per table 74 the default value is allowed to be
singular. I take that to imply that an lvalue-rvalue conversion on it2 is
undefined behavior.


Best

Kai-Uwe Bux

Daniel Krügler

unread,
Aug 24, 2010, 8:05:18 PM8/24/10
to

Here you are attempting to read the value of
a potentially non-initialized variable. Any
operation different from destroying or assigning
*to* an uninitialized object causes undefined
behaviour.

> return 0;
> }
>
> More elaborated example that show why we need this to work (and it
> does in all C++ compilers except VS2010).
>
> #include <list>
> int main() {
> typedef std::list< int > IntList;
> typedef IntList::iterator IntIterator;
>
> IntList integerList;
>
> struct A
> {
> IntIterator it;
> };
>
> A a, b;
> a.it = integerList.end();
>
> a = b; // << here it crasches due to the test:
> _Adopt(_Right._Myproxy->_Mycont); in xutility (STL)
>
> return 0;
> }

The iterator requirements allow for types that
are uninitialized after default-initialization.
This basically means that above code may or may
not cause undefined behaviour depending on the
fact, whether default-initialization leads to
such a "partially-formed" state. To prevent this
problem, you just need to ensure that your
iterator source is value-initialized, based on
[iterator.requirements.general]/6:

"Results of most expressions are undefined for
singular values; the only exceptions are destroying
an iterator that holds a singular value, the
assignment of a non-singular value to an iterator
that holds a singular value, and, for iterators
that satisfy the DefaultConstructible requirements,
using a value-initialized iterator as the source
of a copy or move operation."

[Note that the term "singular value" is misleading
in this context, see library issue #1213, but that
is a different side-aspect of this description].

Independent on the question how to make that work
I still wonder why you expect that given;

T x, y;

you are requiring that

x = y;

"works". The DefaultConstructible requirements
specifically allow for an uninitialized object
state, but don't allow for reading it. Thus, I
don't see any convincing rationale provided that
would explain your rather strong assertion for
an "example that show why we need this to work".
Why is this so important to make it work? Assuming,
you have such reason, just change

struct A
{
IntIterator it;
};

A a, b;

to

struct A
{
IntIterator it;
};

A a = {}, b = {};

which guarantees value-initialization.

HTH & Greetings from Bremen,

Daniel Krügler

red floyd

unread,
Aug 24, 2010, 8:04:10 PM8/24/10
to
On Aug 24, 2:00 pm, backminator <backmina...@gmail.com> wrote:
> Hi all.
>
> I've been running c++ code under Linux gcc 2.93->4.4.3, OSX, and
> Windows (VisualStudio 2005-2008) for > 3 years.
> Now we are upgrading to VS2010 which supports C++00. We now suddenly
> got a problem related to iterators.
> The question is really, is the code below valid or not? It runs ok on
> every instance of a compiler I can get my hands on, except VS2010.
>
> It crasches on the assignment of the iterator, where it is trying to
> dereference a null pointer.
> My question is not really about this and that implementation of
> compiler, its more of a C++, is this ok question.
> Using unassigned iterators is not valid. The question is what the
> below example shows?

Undefined behavior. Anything can happen.

Seungbeom Kim

unread,
Aug 25, 2010, 7:09:00 PM8/25/10
to
On 2010-08-24 14:00, backminator wrote:
>
> It crasches on the assignment of the iterator, where it is trying to
> dereference a null pointer.
> My question is not really about this and that implementation of
> compiler, its more of a C++, is this ok question.
> Using unassigned iterators is not valid. The question is what the
> below example shows?
>
[...]

>
> So at any point, where you happens to assign a valid iterator the
> value of an unassigned one, it crasches in VisualStudio 2010.
> We might be able to refactor all the code having iterators in the
> default constructor of the class, but Im not sure we want to ;-)
>
>
>
> #include <list>
> int main()
> {
> typedef std::list< int > IntList;
>
> IntList integerList;
> typedef IntList::iterator IntIterator;
>
> IntIterator it1 = hej.end();
> IntIterator it2;
>
> it1 = it2;
> return 0;
> }

An uninitialized iterator has an indeterminate(singular) value, and
reading the value causes undefined behavior, as in

int a = 0, b;
a = b;

4.1[Lvalue-to-rvalue conversion]/1:
"[...] or if the object is uninitialized, a program that necessitates
this conversion has undefined behavior."

24.1.3[Forward iterators]/1, Table 74 also specifically mentions that
a default-constructed iterator might have a singular value.

--
Seungbeom Kim

0 new messages