g++ const 'this' problems

Discussion in 'C++' started by John Calcote, Dec 19, 2003.

  1. John Calcote

    John Calcote Guest

    I'm not sure is there's a g++ specific newsgroup...

    g++ is telling me there's a const-related problem with my source code
    and I just don't see it. Now, I don't know that it means much, but VC7
    doesn't see the problem either:

    ----snip-snip-snip----

    #include <string>
    #include <set>

    using namespace std;

    class X {
    class Y {
    set<string> _bound;
    public:
    void Bind(const string & x);
    };

    set<Y> _requests;
    public:
    void ApplyChanges(const set<string> & changes);
    };

    void X::Y::Bind(const std::string & data)
    {
    _bound.insert(data);
    }

    void X::ApplyChanges(const set<string> & changes)
    {
    set<Y>::iterator rip;
    set<string>::const_iterator ip;
    for (ip = changes.begin(); ip != changes.end(); ++ip)
    for (rip = _requests.begin(); rip != _requests.end(); ++rip)
    rip->Bind(*ip);
    }

    int main(void)
    {
    X x;
    return 0;
    }

    ----snip-snip-snip----

    This source causes the following error messages:

    test.cpp: In member function `void X::ApplyChanges(const
    std::set<std::string,
    std::less<std::string>, std::allocator<std::string> >&)':
    test.cpp:30: passing `const X::Y' as `this' argument of `void
    X::Y::Bind(const
    std::string&)' discards qualifiers

    Now, I can't for the life of me see how I'm violating const rules
    here. I'm not passing a const 'this' pointer. I'm passing a const
    parameter, true, but it's not the this pointer.

    Any ideas?
    John
     
    John Calcote, Dec 19, 2003
    #1
    1. Advertising

  2. John Calcote wrote:
    > I'm not sure is there's a g++ specific newsgroup...
    >
    > g++ is telling me there's a const-related problem with my source code
    > and I just don't see it. Now, I don't know that it means much, but VC7
    > doesn't see the problem either:
    >
    > ----snip-snip-snip----
    >
    > #include <string>
    > #include <set>
    >
    > using namespace std;
    >
    > class X {
    > class Y {
    > set<string> _bound;
    > public:
    > void Bind(const string & x);
    > };
    >
    > set<Y> _requests;
    > public:
    > void ApplyChanges(const set<string> & changes);
    > };
    >
    > void X::Y::Bind(const std::string & data)
    > {
    > _bound.insert(data);
    > }
    >
    > void X::ApplyChanges(const set<string> & changes)
    > {
    > set<Y>::iterator rip;
    > set<string>::const_iterator ip;
    > for (ip = changes.begin(); ip != changes.end(); ++ip)
    > for (rip = _requests.begin(); rip != _requests.end(); ++rip)
    > rip->Bind(*ip);


    I changed that code to this:

    Y * pr_rip = &(* rip);
    pr_rip->Bind(*ip);

    gcc_constthis.cpp:30: error: invalid conversion from `const X::Y*' to
    `X::Y*'

    It seems at though it is a const_iterator.

    Looks like a gcc bug.

    It compiles fine on VC++7.1.

    > }
    >
    > int main(void)
    > {
    > X x;
    > return 0;
    > }
    >
    > ----snip-snip-snip----
    >
    > This source causes the following error messages:
    >
    > test.cpp: In member function `void X::ApplyChanges(const
    > std::set<std::string,
    > std::less<std::string>, std::allocator<std::string> >&)':
    > test.cpp:30: passing `const X::Y' as `this' argument of `void
    > X::Y::Bind(const
    > std::string&)' discards qualifiers
    >
    > Now, I can't for the life of me see how I'm violating const rules
    > here. I'm not passing a const 'this' pointer. I'm passing a const
    > parameter, true, but it's not the this pointer.
    >
    > Any ideas?
    > John
     
    Gianni Mariani, Dec 19, 2003
    #2
    1. Advertising

  3. John Calcote

    Artie Gold Guest

    John Calcote wrote:
    > I'm not sure is there's a g++ specific newsgroup...
    >

    There is: news:gnu.g++.help

    [snip]
    [Everything else dealt with elsethread.]

    Cheers,
    --ag

    --
    Artie Gold -- Austin, Texas
    Oh, for the good old days of regular old SPAM.
     
    Artie Gold, Dec 19, 2003
    #3
  4. John Calcote

    tom_usenet Guest

    On 19 Dec 2003 14:27:10 -0800, (John Calcote)
    wrote:

    >I'm not sure is there's a g++ specific newsgroup...
    >
    >g++ is telling me there's a const-related problem with my source code
    >and I just don't see it. Now, I don't know that it means much, but VC7
    >doesn't see the problem either:


    It seems GCC is ahead of the game, already having implemented this
    defect report:
    http://std.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#103

    Tom

    C++ FAQ: http://www.parashift.com/c -faq-lite/
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
     
    tom_usenet, Dec 19, 2003
    #4
  5. John Calcote wrote in news::

    > I'm not sure is there's a g++ specific newsgroup...
    >
    >g++ is telling me there's a const-related problem with my source code
    > and I just don't see it. Now, I don't know that it means much, but VC7
    > doesn't see the problem either:
    >


    VC7 is wrong, If there is any doubt about this it compiles this
    nonsence:

    #include <iostream>
    #include <ostream>
    #include <set>

    using namespace std;

    int main()
    {
    set< int > si;
    for ( int i = 0; i < 10; ++i ) si.insert( i );

    *si.find( 2 ) = 4;

    set< int >::iterator ptr, lim;

    for ( ptr = si.begin(), lim = si.end(); ptr != lim; ++ptr )
    {
    cout << *ptr << endl;
    }
    }

    This compiles with VC 7.1 ( Dinkumware Standard library 313 ).

    Anyway, your original code with some addition's/fixes:

    #include <string>
    #include <set>

    using namespace std;

    class X {
    class Y {
    mutable set<string> _bound;
    int key;
    static int static_key;

    public:

    void Bind(const string & x) const;
    Y() : key( ++static_key ) {}
    bool operator < ( Y const &rhs ) const
    {
    return key < rhs.key;
    }
    };

    set<Y> _requests;
    public:
    void ApplyChanges(const set<string> & changes);
    void add_request()
    {
    _requests.insert( Y() );
    }
    };

    int X::Y::static_key = 0;

    void X::Y::Bind(const std::string & data) const
    {
    _bound.insert(data);
    }

    void X::ApplyChanges(const set<string> & changes)
    {
    set<Y>::iterator rip;
    set<string>::const_iterator ip;
    for (ip = changes.begin(); ip != changes.end(); ++ip)
    for (rip = _requests.begin(); rip != _requests.end(); ++rip)
    rip->Bind(*ip);
    }


    int main(void)
    {
    X x;

    x.add_request();

    set< string > ss;

    ss.insert( " a " );

    x.ApplyChanges( ss );

    return 0;
    }

    >
    > This source causes the following error messages:
    >
    > test.cpp: In member function `void X::ApplyChanges(const
    > std::set<std::string,
    > std::less<std::string>, std::allocator<std::string> >&)':
    > test.cpp:30: passing `const X::Y' as `this' argument of `void
    > X::Y::Bind(const
    > std::string&)' discards qualifiers
    >
    > Now, I can't for the life of me see how I'm violating const rules
    > here. I'm not passing a const 'this' pointer. I'm passing a const
    > parameter, true, but it's not the this pointer.
    >


    std::set< T > should store T const's not T's, your looking at the wrong
    "this", the error message is refering to the Y const * you were
    using as a "this" paramiter to Y::Bind().

    Note all the cruft I added to get this to compile, you might want to
    think about changing, set< Y > _requests; to std::map< SomeKey, Y >.

    HTH.

    Rob.
    --
    http://www.victim-prime.dsl.pipex.com/
     
    Rob Williscroft, Dec 19, 2003
    #5
  6. John Calcote

    tom_usenet Guest

    On 19 Dec 2003 23:55:57 GMT, Rob Williscroft
    <> wrote:

    >VC7 is wrong, If there is any doubt about this it compiles this
    >nonsence:
    >
    >#include <iostream>
    >#include <ostream>
    >#include <set>
    >
    >using namespace std;
    >
    >int main()
    >{
    > set< int > si;
    > for ( int i = 0; i < 10; ++i ) si.insert( i );
    >
    > *si.find( 2 ) = 4;
    >
    > set< int >::iterator ptr, lim;
    >
    > for ( ptr = si.begin(), lim = si.end(); ptr != lim; ++ptr )
    > {
    > cout << *ptr << endl;
    > }
    >}
    >
    >This compiles with VC 7.1 ( Dinkumware Standard library 313 ).


    And so it should - the code is well-formed according to the current
    standard (set::value_type is non-const according to std::set's
    synopsis, set::iterator::value_type is also non-const according to
    container requirements). Obviously the code has undefined behaviour
    (since a key is modified in such a way as to affect its ordering). See

    http://std.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#103

    Tom

    C++ FAQ: http://www.parashift.com/c -faq-lite/
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
     
    tom_usenet, Dec 20, 2003
    #6
  7. John Calcote

    Jerry Coffin Guest

    In article <Xns9456F34B32962ukcoREMOVEfreenetrtw@195.129.110.201>,
    says...

    [ ... ]

    > VC7 is wrong, If there is any doubt about this it compiles this
    > nonsence:


    This is one of those places that's open to a lot of argument, at best.
    Despite being more or less nonsensical, the standard requires a
    conforming implementation to accept the code.

    In any case, the library working group of the C++ committee has drafted
    a proposal for fixing this part of the standard, and it'll almost
    certainly end up in a TC or somesuch eventually. The proposal basically
    says that for a set (among other things) the key will be immutable, and
    both iterator and const_iterator will be const, so you won't be able to
    modify the key as you've done.

    Nonetheless, that's not part of the standard yet, so to follow the
    standard as it currently stands, the compiler must accept the code.
    There's a comment in the standard that more or less implies that if you
    modify a key, the modification should not alter the ordering. Based on
    that, I think a case could be made for saying that your code has
    undefined behavior, meaning nothing the compiler does with it is really
    wrong.

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Dec 20, 2003
    #7
  8. Jerry Coffin wrote:
    > In article <Xns9456F34B32962ukcoREMOVEfreenetrtw@195.129.110.201>,
    > says...
    >
    > [ ... ]
    >
    >
    >>VC7 is wrong, If there is any doubt about this it compiles this
    >>nonsence:

    >
    >
    > This is one of those places that's open to a lot of argument, at best.
    > Despite being more or less nonsensical, the standard requires a
    > conforming implementation to accept the code.
    >
    > In any case, the library working group of the C++ committee has drafted
    > a proposal for fixing this part of the standard, and it'll almost
    > certainly end up in a TC or somesuch eventually. The proposal basically
    > says that for a set (among other things) the key will be immutable, and
    > both iterator and const_iterator will be const, so you won't be able to
    > modify the key as you've done.
    >
    > Nonetheless, that's not part of the standard yet, so to follow the
    > standard as it currently stands, the compiler must accept the code.
    > There's a comment in the standard that more or less implies that if you
    > modify a key, the modification should not alter the ordering. Based on
    > that, I think a case could be made for saying that your code has
    > undefined behavior, meaning nothing the compiler does with it is really
    > wrong.
    >


    Strictly speaking, you're 100% correct, however, in any case, gcc
    behaviour is probably is *wrong* by the standard but its behaviour
    (iterator is const) is exactly the right practical answer for me.

    It just saved the OP hours of endless problems.

    It would be better to have an implementation of a set that allows you to
    "re-insert" an object rather than an erase and insert but the API for
    STL containers seem to avoid allowing those kinds of more efficient (yep
    more complex) uses of containers. So you end up placing those
    complications in the application.
     
    Gianni Mariani, Dec 20, 2003
    #8
  9. John Calcote

    Jerry Coffin Guest

    In article <bs2akc$>,
    says...

    [ ... ]

    > Strictly speaking, you're 100% correct, however, in any case, gcc
    > behaviour is probably is *wrong* by the standard but its behaviour
    > (iterator is const) is exactly the right practical answer for me.


    Right -- that's exactly why I said it was open to argument instead of
    saying something like "No, VC7 is right and gcc is wrong." The reality
    is that pretty much everybody agrees that the standard is wrong the way
    it stands, but it's still pretty hard for me to condemn somebody for
    following the standard.

    The same situation arises (in reverse) with exception specifications: as
    specified, exception specifications are flawed to the point that
    enforcing them is really a bad idea. VC++ will give you a warning in a
    case like this:

    void junk() throw() { throw 1; }

    where it can show by static analysis that the code throws an exception
    it says it won't. OTOH, it does NOT do the run-time enforcement that
    causes the real problem. In this case, gcc is the one that follows the
    standard (by calling unexpected() in this case) even though it's pretty
    clearly the wrong thing to do.

    In the end, there's no obvious, clear-cut way to handle things like this
    -- especially when there's usually some room for argument that the way
    the standard specifies things does have at least some minimal advantage.
    In the case of modifying the key in a set, if you're SURE your change in
    the key won't alter the order of elements in the set, then it's fastest
    to modify it in place. Likewise, calls to unexpected() are likely to
    help you find incorrect exceptions being thrown fairly quickly -- if
    you're certain your testing will turn up all the problems before the
    code is released, it _might_ work out reasonably well (from my comments
    above, you can probably guess that I consider that unlikely at best).

    --
    Later,
    Jerry.

    The universe is a figment of its own imagination.
     
    Jerry Coffin, Dec 21, 2003
    #9
  10. John Calcote

    John Calcote Guest

    tom_usenet <> wrote in message news:<>...
    > On 19 Dec 2003 14:27:10 -0800, (John Calcote)
    > wrote:
    >
    > It seems GCC is ahead of the game, already having implemented this
    > defect report:
    > http://std.dkuug.dk/jtc1/sc22/wg21/docs/lwg-defects.html#103


    Tom (and everyone),

    Thanks for the concise responses to my question. I now thoroughly
    understand the problem domain. IMHO, Microsoft's approach to this
    problem in the standard is more useful, if not necessarily more
    correct.

    As a programmer, I understand the fundamental concept of a set. It
    would not occur to me to try to modify the key data in a set element
    while it was in the set. While I could see doing this accidentally, I
    don't necessarily think a compiler or library should prevent me from
    doing it, because such precautions also prevent me from doing
    reasonable things with set elements - such as changing non-key data.

    As a side note, before I posted this message, I had changed Bind to
    const, and then marked the data members touched by Bind as mutable. I
    don't like this "solution" at all because frankly, it's nothing short
    of casting away const on 'this', which lacks elegance, and generally
    indicates design flaws. It's a hack required to accomplish something
    entirely legitimate, and made necessary by an overbearing constraint.
    Such constraints go against the grain of the original C and C++
    language goals (remember the "shoot yourself in the foot" analogies
    that used to float around years ago?)

    In any case, I think I'll switch container types because my code has
    to be portable to Windows, NetWare and 5 flavors of Unix. I can't take
    a chance that a different interpretation of the standard in this area
    will cause some future port to fail in a way that I can foresee and
    prevent.

    John
     
    John Calcote, Dec 22, 2003
    #10
    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. Replies:
    11
    Views:
    1,149
  2. Javier
    Replies:
    2
    Views:
    618
    James Kanze
    Sep 4, 2007
  3. 0m
    Replies:
    26
    Views:
    1,170
    Tim Rentsch
    Nov 10, 2008
  4. fungus
    Replies:
    13
    Views:
    942
    fungus
    Oct 31, 2008
  5. Replies:
    2
    Views:
    561
    Andrew Koenig
    Feb 9, 2009
Loading...

Share This Page