By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,918 Members | 2,279 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,918 IT Pros & Developers. It's quick & easy.

g++ const 'this' problems

P: n/a
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
Jul 22 '05 #1
Share this Question
Share on Google+
9 Replies


P: n/a
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


Jul 22 '05 #2

P: n/a
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.

Jul 22 '05 #3

P: n/a
On 19 Dec 2003 14:27:10 -0800, jc******@novell.com (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/d...fects.html#103

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #4

P: n/a
John Calcote wrote in news:ab**************************@posting.google.c om:
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/
Jul 22 '05 #5

P: n/a
On 19 Dec 2003 23:55:57 GMT, Rob Williscroft
<rt*@freenet.REMOVE.co.uk> 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/d...fects.html#103

Tom

C++ FAQ: http://www.parashift.com/c++-faq-lite/
C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
Jul 22 '05 #6

P: n/a
In article <Xn**********************************@195.129.110. 201>,
rt*@freenet.REMOVE.co.uk 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.
Jul 22 '05 #7

P: n/a
Jerry Coffin wrote:
In article <Xn**********************************@195.129.110. 201>,
rt*@freenet.REMOVE.co.uk 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.
Jul 22 '05 #8

P: n/a
In article <bs********@dispatch.concentric.net>, gi*******@mariani.ws
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.
Jul 22 '05 #9

P: n/a
tom_usenet <to********@hotmail.com> wrote in message news:<1o********************************@4ax.com>. ..
On 19 Dec 2003 14:27:10 -0800, jc******@novell.com (John Calcote)
wrote:

It seems GCC is ahead of the game, already having implemented this
defect report:
http://std.dkuug.dk/jtc1/sc22/wg21/d...fects.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
Jul 22 '05 #10

This discussion thread is closed

Replies have been disabled for this discussion.