STL list code fires assertion in VC++ 2005, but not in VC++ 2003.

Discussion in 'C++' started by Jason Doucette, Jun 28, 2007.

  1. I'm getting an assertion fire from a list iterator being checked
    against NULL. This did not occur in VC++ 2003 (v7.1). Are there
    changes that have been made to the STL between these versions that I
    should know about? Any resources I should check into?

    thanks,
    Jason
     
    Jason Doucette, Jun 28, 2007
    #1
    1. Advertising

  2. Jason Doucette wrote:
    > I'm getting an assertion fire from a list iterator being checked
    > against NULL.


    Why are you doing that?

    > This did not occur in VC++ 2003 (v7.1). Are there
    > changes that have been made to the STL between these versions that I
    > should know about?


    Probably. Actually, very likely.

    > Any resources I should check into?


    FAQ 5.8

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 28, 2007
    #2
    1. Advertising

  3. > > I'm getting an assertion fire from a list iterator being checked
    > > against NULL.

    >
    > Why are you doing that?


    Because I have a function that reports whether or not an element is in
    the list. If it is, it returns an iterator to that element. If it's
    not, then it returns NULL.

    Is this bad? It worked fine in VC++ 2003. But, the internals of the
    STL list class doesn't seem to like it, anymore.

    > > This did not occur in VC++ 2003 (v7.1). Are there
    > > changes that have been made to the STL between these versions that I
    > > should know about?

    >
    > Probably. Actually, very likely.


    I recall reading something a long time ago that they had made some
    changes. I can't seem to find a decent resource on this, though.

    > > Any resources I should check into?

    >
    > FAQ 5.8


    Of what manual? The C++ Standard? I don't think it's publicly
    available.

    Thanks, Victor.

    Jason
     
    Jason Doucette, Jun 28, 2007
    #3
  4. > FAQ 5.8

    Sorry, you mean the newsgroup FAQ, obviously, duh. I had forgotten
    which newsgroup I was replying to.

    cheers,
    Jason
     
    Jason Doucette, Jun 28, 2007
    #4
  5. Jason Doucette

    Marcus Kwok Guest

    Jason Doucette <> wrote:
    > I'm getting an assertion fire from a list iterator being checked
    > against NULL. This did not occur in VC++ 2003 (v7.1). Are there
    > changes that have been made to the STL between these versions that I
    > should know about? Any resources I should check into?


    MS added "checked iterators" in VS 2005. See:
    http://msdn2.microsoft.com/en-us/library/aa985965(VS.80).aspx

    If you need more info on them, you should probably consult a Visual
    Studio group.

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Jun 28, 2007
    #5
  6. > Sorry, you mean the newsgroup FAQ, obviously, duh. I had forgotten
    > which newsgroup I was replying to.


    ....which is parashift.com's C++ FAQ Lite, which is not a FAQ just for
    this group.

    5.8 is about posting non-working code questions:
    http://www.parashift.com/c -faq-lite/how-to-post.html#faq-5.8
    Is this what you mean?

    If so, I am not asking anyone to fix my code. I'm looking for a
    resource (that I can research myself) about what changes were made to
    the STL implementation from VC++ 2003 to VC++ 2005, so I can determine
    what I'm now doing wrong.

    Thanks,
    Jason
     
    Jason Doucette, Jun 28, 2007
    #6
  7. Jason Doucette

    Marcus Kwok Guest

    Jason Doucette <> wrote:
    >> > I'm getting an assertion fire from a list iterator being checked
    >> > against NULL.

    >>
    >> Why are you doing that?

    >
    > Because I have a function that reports whether or not an element is in
    > the list. If it is, it returns an iterator to that element. If it's
    > not, then it returns NULL.


    Oh, I misinterpreted your original post. For containers, usually
    functions that work with them are passed a start iterator
    (container.begin()) and a one-past-the-last iterator (container.end()).
    If the element isn't found, then the one-past-the-last iterator is
    returned.

    > Is this bad? It worked fine in VC++ 2003. But, the internals of the
    > STL list class doesn't seem to like it, anymore.


    Pointers are valid iterators, so my guess is that in VC++ 2003, the
    iterators were implemented as pointers, so the comparison with NULL
    worked. But then, in 2005, they added the checked iterators, which is
    probably a whole class instead of a simple pointer, so the comparison
    with NULL is no longer valid.

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Jun 28, 2007
    #7
  8. On 2007-06-28 21:30, Jason Doucette wrote:
    > I'm getting an assertion fire from a list iterator being checked
    > against NULL. This did not occur in VC++ 2003 (v7.1). Are there
    > changes that have been made to the STL between these versions that I
    > should know about? Any resources I should check into?


    No, the STL is probably the same. But the implementation in VS might
    have changed. Consider yourself lucky this probably means you have
    uncovered a hidden bug in your code. By the way, what do you mean with
    the iterator being checked against NULL? Who did the check?

    --
    Erik Wikström
     
    =?ISO-8859-1?Q?Erik_Wikstr=F6m?=, Jun 28, 2007
    #8
  9. > MS added "checked iterators" in VS 2005. See:http://msdn2.microsoft.com/en-us/library/aa985965(VS.80).aspx

    Marcus, this link lead me to the page I was looking for:

    Breaking Changes in the Standard C++ Library
    http://msdn2.microsoft.com/en-us/library/aa985946(VS.80).aspx

    Specifically, this section:

    "Debug Iterators
    Applications built with a debug version of the C-Runtime Library and
    which use iterators incorrectly might begin to see asserts at runtime.
    To disable these asserts, you must define _HAS_ITERATOR_DEBUGGING to
    0. For more information, see Debug Iterator Support."

    So, I have been using iterators incorrectly this entire time. Perhaps
    it has to do with me setting them to NULL, or not initializing them
    explicitly to a value that makes sense. I am not sure, I'll have to
    research this.

    Thanks for your help,
    Jason
     
    Jason Doucette, Jun 28, 2007
    #9
  10. Jason Doucette

    Alan Johnson Guest

    Jason Doucette wrote:
    >> Sorry, you mean the newsgroup FAQ, obviously, duh. I had forgotten
    >> which newsgroup I was replying to.

    >
    > ...which is parashift.com's C++ FAQ Lite, which is not a FAQ just for
    > this group.
    >
    > 5.8 is about posting non-working code questions:
    > http://www.parashift.com/c -faq-lite/how-to-post.html#faq-5.8
    > Is this what you mean?
    >
    > If so, I am not asking anyone to fix my code. I'm looking for a
    > resource (that I can research myself) about what changes were made to
    > the STL implementation from VC++ 2003 to VC++ 2005, so I can determine
    > what I'm now doing wrong.
    >
    > Thanks,
    > Jason
    >


    Victor was almost certainly trying to hint that you should post some
    code. Without seeing code that demonstrates the error, the best we can
    do is guess.

    From the rest of this thread, it appears to me that you are under the
    impression that iterators are pointers, which is not (necessarily) true.
    Setting an iterator to NULL, for example, doesn't make any sense. You
    should treat an iterator as an opaque object that can only be used in
    the expressions guaranteed by the standard. If you don't have a copy of
    the standard, the following is reasonably close to correct:
    http://www.sgi.com/tech/stl/table_of_contents.html

    The equivalent of a NULL pointer for iterators is the past-the-end
    iterator (what you get from container.end()). The correct way to do
    what you described elsewhere in the thread would look something like this:

    template <typename T>
    typename std::list<T>::iterator some_algorithm(
    const std::list<T> & lst, const T & value)
    {
    // Do whatever and return an iterator.

    // Not found, return the past the end iterator.
    return lst.end();
    }

    void some_function()
    {
    std::list<int> lst;
    // ...

    std::list<int>::iterator i = some_algorithm(lst, 42);
    if (i == lst.end())
    {
    // Handle not found case.
    }
    }

    --
    Alan Johnson
     
    Alan Johnson, Jun 28, 2007
    #10
  11. Jason Doucette

    Marcus Kwok Guest

    Jason Doucette <> wrote:
    > So, I have been using iterators incorrectly this entire time. Perhaps
    > it has to do with me setting them to NULL, or not initializing them
    > explicitly to a value that makes sense.


    Yes, I think this is the case. See Alan Johnson's post or my other post
    for suggestions on how you should handle the not-found case instead of
    trying to return NULL.

    --
    Marcus Kwok
    Replace 'invalid' with 'net' to reply
     
    Marcus Kwok, Jun 28, 2007
    #11
  12. > No, the STL is probably the same. But the implementation in VS might
    > have changed. Consider yourself lucky this probably means you have
    > uncovered a hidden bug in your code. By the way, what do you mean with
    > the iterator being checked against NULL? Who did the check?


    I have a function that checks a list for some data, by iterating
    through it. If it finds the element, it returns the iterator to it.
    If not, it returns NULL. The caller of this function checks the
    return value (an iterator) to see if it's NULL or not. (Kind of like
    a pointer, it either points to something, or NULL...)

    std::list<myStruct> myList;
    std::list<myStruct>::iterator myIterator;

    for (myIterator = myList.begin(); myIterator != myList.end();
    myIterator++)
    {
    if (myIterator != NULL) <----- BANG!
    }

    thanks,
    Jason
     
    Jason Doucette, Jun 28, 2007
    #12
  13. > Oh, I misinterpreted your original post. For containers, usually
    > functions that work with them are passed a start iterator
    > (container.begin()) and a one-past-the-last iterator (container.end()).
    > If the element isn't found, then the one-past-the-last iterator is
    > returned.


    Oh... so I should probably use this concept, as well. To be
    consistent. In fact, it may be the only correct way to do it.

    I should note that the assertion fires when the iterator is NOT NULL,
    but is a legit element. It appears that it cannot be compared to
    NULL. It used to be ok to treat it like any old pointer (perhaps
    because VC++ 7.1 didn't care), but now it seems this is not ok (which
    was likely always the case, for STL).

    > Pointers are valid iterators, so my guess is that in VC++ 2003, the
    > iterators were implemented as pointers, so the comparison with NULL
    > worked. But then, in 2005, they added the checked iterators, which is
    > probably a whole class instead of a simple pointer, so the comparison
    > with NULL is no longer valid.


    Right. The checked iterators do check that they are in range. But,
    my issue isn't an out-of-range one (although, eventually, it will be
    when the function that does a search fails, and wants to return
    NULL). My current issue is that an iterator that points to a real
    element cannot be compared to NULL. Your diagnosis sounds correct.

    Thanks, Marcus
    Jason
     
    Jason Doucette, Jun 28, 2007
    #13
  14. > Victor was almost certainly trying to hint that you should post some
    > code. Without seeing code that demonstrates the error, the best we can
    > do is guess.


    Right. I didn't want people to solve my code problem. I just wanted
    a resource section so I could solve it myself. But, you guys have
    done an amazing job, nonetheless.

    > From the rest of this thread, it appears to me that you are under the
    > impression that iterators are pointers, which is not (necessarily) true.
    > Setting an iterator to NULL, for example, doesn't make any sense. You
    > should treat an iterator as an opaque object that can only be used in
    > the expressions guaranteed by the standard.


    I think this is exactly my problem.

    > If you don't have a copy of
    > the standard, the following is reasonably close to correct:
    > http://www.sgi.com/tech/stl/table_of_contents.html


    Thank you.

    > The equivalent of a NULL pointer for iterators is the past-the-end
    > iterator (what you get from container.end()). The correct way to do
    > what you described elsewhere in the thread would look something like this:
    >
    > template <typename T>
    > typename std::list<T>::iterator some_algorithm(
    > const std::list<T> & lst, const T & value)
    > {
    > // Do whatever and return an iterator.
    >
    > // Not found, return the past the end iterator.
    > return lst.end();
    > }
    >
    > void some_function()
    > {
    > std::list<int> lst;
    > // ...
    >
    > std::list<int>::iterator i = some_algorithm(lst, 42);
    > if (i == lst.end())
    > {
    > // Handle not found case.
    > }
    > }


    Right, thanks a lot, Alan! This is exactly what I will need to
    change.

    Jason
     
    Jason Doucette, Jun 28, 2007
    #14
  15. Jason Doucette wrote:
    >> No, the STL is probably the same. But the implementation in VS might
    >> have changed. Consider yourself lucky this probably means you have
    >> uncovered a hidden bug in your code. By the way, what do you mean
    >> with the iterator being checked against NULL? Who did the check?

    >
    > I have a function that checks a list for some data, by iterating
    > through it. If it finds the element, it returns the iterator to it.
    > If not, it returns NULL. The caller of this function checks the
    > return value (an iterator) to see if it's NULL or not. (Kind of like
    > a pointer, it either points to something, or NULL...)
    >
    > std::list<myStruct> myList;
    > std::list<myStruct>::iterator myIterator;
    >
    > for (myIterator = myList.begin(); myIterator != myList.end();
    > myIterator++)
    > {
    > if (myIterator != NULL) <----- BANG!
    > }


    This code isn't even remotely close to the real code, Jason. There
    is no "function", there is no "caller"...

    Does the caller have access to the list? If he does, returning the
    'end()' is much better than relying on the iterator's comparability
    with NULL. It he does not, why does it have to be an iterator? Make
    your function return a pointer, to the contained element if success
    and NULL if not.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 28, 2007
    #15
  16. > This code isn't even remotely close to the real code, Jason. There
    > is no "function", there is no "caller"...


    Sorry, I determined the function / caller wasn't the issue. It was
    the iterator being compared to NULL, when it was set to being
    something legitimate (between myList.begin() and myList.end()). So,
    instead of making the problem more complex, I shortened it down as
    much as I could, to remove all things that were irrelevant.

    I believe the issue is resolved... I've been using iterators like
    pointers, which is no longer safe since the switch from VC++7.1 to VC+
    +8.0, as mentioned a few times elsewhere. So, I'll rework my code as
    you and others have suggested, and I am confident it will work. I'll
    post back and let you know.

    > Does the caller have access to the list? If he does, returning the
    > 'end()' is much better than relying on the iterator's comparability
    > with NULL. It he does not, why does it have to be an iterator? Make
    > your function return a pointer, to the contained element if success
    > and NULL if not.


    Yes, the caller does have access to the list, so returning end() is an
    option, and sounds like something much better to use. I didn't know
    it was standard practice to use this for something "out of range". (I
    guess pointers / NULL just seemed intuitive.)

    The caller makes use of the information within the element it gets (if
    not NULL), and then deletes it from the list. So, having the iterator
    to this element is ideal, since deleting it via erase() is very easy,
    as it takes in an iterator to the element you want erased.

    Thanks for your time,
    Jason
     
    Jason Doucette, Jun 28, 2007
    #16
  17. Jason Doucette

    Gavin Deane Guest

    On 28 Jun, 22:53, Jason Doucette <> wrote:
    > > Does the caller have access to the list? If he does, returning the
    > > 'end()' is much better than relying on the iterator's comparability
    > > with NULL. It he does not, why does it have to be an iterator? Make
    > > your function return a pointer, to the contained element if success
    > > and NULL if not.

    >
    > Yes, the caller does have access to the list, so returning end() is an
    > option, and sounds like something much better to use. I didn't know
    > it was standard practice to use this for something "out of range". (I
    > guess pointers / NULL just seemed intuitive.)
    >
    > The caller makes use of the information within the element it gets (if
    > not NULL), and then deletes it from the list. So, having the iterator
    > to this element is ideal, since deleting it via erase() is very easy,
    > as it takes in an iterator to the element you want erased.


    It is ideal - and that's not by happy coincidence, it's by design. Now
    you've discovered the idomatic way to use iterators, have a look at
    how the standard library algoriths fit together with containers and
    iterators. For example, it sounds like there could be a way to replace
    your function with a single call to std::find. Might or might not be
    easy - and if it is, it might or might not be worth it if you've got
    your function already written and tested, but it will be useful
    knowledge for next time.

    Gavin Deane
     
    Gavin Deane, Jun 28, 2007
    #17
  18. Jason Doucette

    red floyd Guest

    Jason Doucette wrote:
    My current issue is that an iterator that points to a real
    > element cannot be compared to NULL.


    Technically, that's always been the case.
     
    red floyd, Jun 28, 2007
    #18
  19. Jason Doucette

    James Kanze Guest

    On Jun 28, 11:53 pm, Jason Doucette <> wrote:

    [...]
    > > Does the caller have access to the list? If he does, returning the
    > > 'end()' is much better than relying on the iterator's comparability
    > > with NULL. It he does not, why does it have to be an iterator? Make
    > > your function return a pointer, to the contained element if success
    > > and NULL if not.


    > Yes, the caller does have access to the list, so returning end() is an
    > option, and sounds like something much better to use. I didn't know
    > it was standard practice to use this for something "out of range". (I
    > guess pointers / NULL just seemed intuitive.)


    It's the usual solution when the user is aware of the list.
    Another, more general solution is to use Barton and Nackman's
    Fallible as a return value.

    > The caller makes use of the information within the element it gets (if
    > not NULL), and then deletes it from the list. So, having the iterator
    > to this element is ideal, since deleting it via erase() is very easy,
    > as it takes in an iterator to the element you want erased.


    This sounds like something Fallible was designed for. The
    client has no need to "know" anything about the list.

    --
    James Kanze (GABI Software) email:
    Conseils en informatique orientée objet/
    Beratung in objektorientierter Datenverarbeitung
    9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
     
    James Kanze, Jun 29, 2007
    #19
  20. > It is ideal - and that's not by happy coincidence, it's by design.

    Yes.

    > Now
    > you've discovered the idomatic way to use iterators, have a look at
    > how the standard library algoriths fit together with containers and
    > iterators. For example, it sounds like there could be a way to replace
    > your function with a single call to std::find. Might or might not be
    > easy - and if it is, it might or might not be worth it if you've got
    > your function already written and tested, but it will be useful
    > knowledge for next time.


    I didn't use std::find, since I had to search for a match of a struct
    field, in a list of such structs. But, I could have defined the
    equality operator == for this struct, and used std::find. The actual
    search code is so small (just a simple for loop), that it's no big
    deal, really. But, I'll keep this in mind for the next time.

    Jason
     
    Jason Doucette, Jun 29, 2007
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sampriti
    Replies:
    4
    Views:
    2,469
  2. =?Utf-8?B?Um9iIFBlbm5lcg==?=

    Asp.Net click event fires on 2000 but not 2003

    =?Utf-8?B?Um9iIFBlbm5lcg==?=, Oct 13, 2004, in forum: ASP .Net
    Replies:
    2
    Views:
    329
    =?Utf-8?B?SGFyaSBOYWly?=
    Oct 18, 2004
  3. =?Utf-8?B?RXJpayBKZW5zZW4=?=

    CodeBehind But Not Postback - Page_Load fires twice

    =?Utf-8?B?RXJpayBKZW5zZW4=?=, Jul 19, 2005, in forum: ASP .Net
    Replies:
    4
    Views:
    3,379
    =?Utf-8?B?RXJpayBKZW5zZW4=?=
    Jul 21, 2005
  4. Replies:
    3
    Views:
    1,032
  5. Replies:
    1
    Views:
    89
    Thomas 'PointedEars' Lahn
    Aug 24, 2007
Loading...

Share This Page