You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@stdcxx.apache.org by "Martin Sebor (JIRA)" <ji...@apache.org> on 2008/01/08 22:24:34 UTC

[jira] Created: (STDCXX-690) [LWG #198] std::reverse_iterator::operator*() invalidates cached values

[LWG #198] std::reverse_iterator::operator*() invalidates cached values
-----------------------------------------------------------------------

                 Key: STDCXX-690
                 URL: https://issues.apache.org/jira/browse/STDCXX-690
             Project: C++ Standard Library
          Issue Type: Bug
          Components: 24. Iterators
    Affects Versions: 4.2.0, 4.1.4, 4.1.3, 4.1.2
            Reporter: Martin Sebor


According to LWG issue 198 (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#198), the implementation of reverse_iterator::operator*() should cache the "base" iterator to prevent dangling references to values cached by it. The test case below demonstrates the problem caused by not doing so:

$ cat t.cpp && make t && ./t
#include <cassert>
#include <iterator>

struct Iterator: std::iterator<std::random_access_iterator_tag, int>
{
    int *cur;
    int cache;

    Iterator (int *p = 0): cur (p) { }
    ~Iterator () { cache = ~cache; }

    reference operator*() { return cache; }

    Iterator& operator++() { cache = *++cur; return *this; }
    Iterator& operator--() { cache = *--cur; return *this; }
};


int main ()
{
    int a[] = { 1, 2, 3 };
    Iterator it (a + sizeof a / sizeof *a);
    std::reverse_iterator<Iterator> rit (it);

    const int &ref = *rit;
    const int val = ref;

    ++rit;
    assert (val == ref);
}
gcc -c -I/home/sebor/stdcxx/include/ansi -D_RWSTDDEBUG   -pthread -I/home/sebor/stdcxx/include -I/build/sebor/stdcxx-gcc-4.1.2-15D/include -I/home/sebor/stdcxx/examples/include  -pedantic -nostdinc++ -g   -W -Wall -Wcast-qual -Winline -Wshadow -Wwrite-strings -Wno-long-long -Wcast-align   t.cpp
gcc t.o -o t -pthread  -L/build/sebor/stdcxx-gcc-4.1.2-15D/lib  -Wl,-R/build/sebor/stdcxx-gcc-4.1.2-15D/lib -lstd15D -lsupc++ -lm 
t: t.cpp:29: int main(): Assertion `val == ref' failed.
Aborted


-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Commented: (STDCXX-690) [LWG #198] std::reverse_iterator::operator*() invalidates cached values

Posted by "Martin Sebor (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/STDCXX-690?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12557043#action_12557043 ] 

Martin Sebor commented on STDCXX-690:
-------------------------------------

I think the issue is bogus and should be reverted. See my post below for details:

-------- Original Message --------
Subject: Re: effects of reverse_iterator::operator*() and operator->()
Date: Tue, 08 Jan 2008 13:47:15 -0700
From: Martin Sebor <se...@roguewave.com>
Reply-To: c++std-lib@accu.org
Organization: Rogue Wave Software, Inc.
To: undisclosed-recipients:;
References: <47...@roguewave.com> <CA...@twcny.rr.com> <47...@roguewave.com> <47...@suse.de>

To: C++ libraries mailing list
Message c++std-lib-19976

I think there's a fundamental problem with issue 198. It acknowledges
that the standard "assumes that pointers and references obtained from
an iterator are still valid after iterator destruction or change"
while at the same time trying to improve reverse_iterator to make it
work with iterators that violate this assumption by caching the last
dereferenced value and invalidating it after a change to the iterator.

The solution of assigning the value of current to a member variable
with the intent of preserving the last value the iterator might have
cached, will in all likelihood overwrite the previously cached value,
and thus effectively invalidate references to elements previously
read from the sequence. I.e., the solution doesn't guarantee that
references to objects obtained from a reverse_iterator remain valid
until throughout the lifetime of the iterator since incrementing or
decrementing the iterator might still invalidate references obtained
from it.

Since apparently no implementation has adopted the resolution of
issue 198 yet and the solution doesn't go far enough I suggest we
revert to the original text and document this as a limitation of
reverse_iterators.

Martin

A test case that demonstrates the problem is below.

#include <cassert>
#include <iterator>

struct Iterator: std::iterator<std::random_access_iterator_tag, int>
{
    int *cur;
    int cache;

    Iterator (int *p = 0): cur (p) { }
    ~Iterator () { cache = ~cache; }

    reference operator*() { return cache; }

    Iterator& operator++() { cache = *++cur; return *this; }
    Iterator& operator--() { cache = *--cur; return *this; }
};


int main ()
{
    int a[] = { 1, 2, 3 };
    Iterator it (a + sizeof a / sizeof *a);

    std::reverse_iterator<Iterator> rit (it);

    const int &ref = *rit;
    const int val = ref;

    ++rit; *rit;
    assert (val == ref);   // holds with LWG #198 implemented

    ++rit; *rit;
    assert (val == ref);   // fails even with LWG #198
}


> [LWG #198] std::reverse_iterator::operator*() invalidates cached values
> -----------------------------------------------------------------------
>
>                 Key: STDCXX-690
>                 URL: https://issues.apache.org/jira/browse/STDCXX-690
>             Project: C++ Standard Library
>          Issue Type: Bug
>          Components: 24. Iterators
>    Affects Versions: 4.1.2, 4.1.3, 4.1.4, 4.2.0
>            Reporter: Martin Sebor
>
> According to LWG issue 198 (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#198), the implementation of reverse_iterator::operator*() should cache the "base" iterator to prevent dangling references to values cached by it. The test case below demonstrates the problem caused by not doing so:
> $ cat t.cpp && make t && ./t
> #include <cassert>
> #include <iterator>
> struct Iterator: std::iterator<std::random_access_iterator_tag, int>
> {
>     int *cur;
>     int cache;
>     Iterator (int *p = 0): cur (p) { }
>     ~Iterator () { cache = ~cache; }
>     reference operator*() { return cache; }
>     Iterator& operator++() { cache = *++cur; return *this; }
>     Iterator& operator--() { cache = *--cur; return *this; }
> };
> int main ()
> {
>     int a[] = { 1, 2, 3 };
>     Iterator it (a + sizeof a / sizeof *a);
>     std::reverse_iterator<Iterator> rit (it);
>     const int &ref = *rit;
>     const int val = ref;
>     ++rit;
>     assert (val == ref);
> }
> gcc -c -I/home/sebor/stdcxx/include/ansi -D_RWSTDDEBUG   -pthread -I/home/sebor/stdcxx/include -I/build/sebor/stdcxx-gcc-4.1.2-15D/include -I/home/sebor/stdcxx/examples/include  -pedantic -nostdinc++ -g   -W -Wall -Wcast-qual -Winline -Wshadow -Wwrite-strings -Wno-long-long -Wcast-align   t.cpp
> gcc t.o -o t -pthread  -L/build/sebor/stdcxx-gcc-4.1.2-15D/lib  -Wl,-R/build/sebor/stdcxx-gcc-4.1.2-15D/lib -lstd15D -lsupc++ -lm 
> t: t.cpp:29: int main(): Assertion `val == ref' failed.
> Aborted

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.


[jira] Updated: (STDCXX-690) [LWG #198] std::reverse_iterator::operator*() invalidates cached values

Posted by "Martin Sebor (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/STDCXX-690?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Martin Sebor updated STDCXX-690:
--------------------------------

    Priority: Minor  (was: Major)

> [LWG #198] std::reverse_iterator::operator*() invalidates cached values
> -----------------------------------------------------------------------
>
>                 Key: STDCXX-690
>                 URL: https://issues.apache.org/jira/browse/STDCXX-690
>             Project: C++ Standard Library
>          Issue Type: Bug
>          Components: 24. Iterators
>    Affects Versions: 4.1.2, 4.1.3, 4.1.4, 4.2.0
>            Reporter: Martin Sebor
>            Priority: Minor
>
> According to LWG issue 198 (http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#198), the implementation of reverse_iterator::operator*() should cache the "base" iterator to prevent dangling references to values cached by it. The test case below demonstrates the problem caused by not doing so:
> $ cat t.cpp && make t && ./t
> #include <cassert>
> #include <iterator>
> struct Iterator: std::iterator<std::random_access_iterator_tag, int>
> {
>     int *cur;
>     int cache;
>     Iterator (int *p = 0): cur (p) { }
>     ~Iterator () { cache = ~cache; }
>     reference operator*() { return cache; }
>     Iterator& operator++() { cache = *++cur; return *this; }
>     Iterator& operator--() { cache = *--cur; return *this; }
> };
> int main ()
> {
>     int a[] = { 1, 2, 3 };
>     Iterator it (a + sizeof a / sizeof *a);
>     std::reverse_iterator<Iterator> rit (it);
>     const int &ref = *rit;
>     const int val = ref;
>     ++rit;
>     assert (val == ref);
> }
> gcc -c -I/home/sebor/stdcxx/include/ansi -D_RWSTDDEBUG   -pthread -I/home/sebor/stdcxx/include -I/build/sebor/stdcxx-gcc-4.1.2-15D/include -I/home/sebor/stdcxx/examples/include  -pedantic -nostdinc++ -g   -W -Wall -Wcast-qual -Winline -Wshadow -Wwrite-strings -Wno-long-long -Wcast-align   t.cpp
> gcc t.o -o t -pthread  -L/build/sebor/stdcxx-gcc-4.1.2-15D/lib  -Wl,-R/build/sebor/stdcxx-gcc-4.1.2-15D/lib -lstd15D -lsupc++ -lm 
> t: t.cpp:29: int main(): Assertion `val == ref' failed.
> Aborted

-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.