/Leigh
Following code compiles on VC9 but not VC10:
#include <set>
class A
{
int m_n;
public:
A(int n):m_n(n){}
void Change(){m_n++;}
bool operator < (const A& rhs) const {return m_n < rhs.m_n;}
};
int main()
{
std::set<A> mySet;
A a(1);
mySet.insert(a);
mySet.begin()->Change();
return 0;
}
Error message on VC10 is
error C2662: 'A::Change' : cannot convert 'this' pointer from 'const A' to 'A &'
Conversion loses qualifiers.
So it seems this is fixed in VC10.
Code compiles on VC10 if you make A::m_n mutable and A::Change() const, but this
will break the set. This trick could be used to make inconsequential changes
(ones that did not change the ordering).
--
David Wilkinson
Visual C++ MVP
I always think mutable is a bit of a hack as const setter functions seem
somehow dodgy to me, instead I have just written the following:
template <typename T, typename Pr = std::less<typename T::key_type const>,
typename Alloc = std::allocator<std::pair<typename T::key_type const, T> > >
class mutable_set : public std::map<typename T::key_type, T, Pr, Alloc>
{
typedef typename T::key_type key_type;
typedef std::map<key_type, T, Pr, Alloc> base_type;
public:
class iterator : public base_type::iterator
{
public:
iterator() {}
iterator(typename base_type::iterator aIterator) :
base_type::iterator(aIterator) {}
T* operator->() const { return
&base_type::iterator::operator*().second; }
T& operator*() const { return base_type::iterator::operator*().second; }
};
class const_iterator : public base_type::const_iterator
{
public:
const_iterator() {}
const_iterator(typename base_type::const_iterator aIterator) :
base_type::const_iterator(aIterator) {}
const T* operator->() const { return
&base_type::const_iterator::operator*().second; }
const T& operator*() const { return
base_type::const_iterator::operator*().second; }
};
public:
iterator insert(const T& aValue)
{
return
iterator(base_type::insert(std::make_pair(static_cast<key_type>(aValue),
aValue)).first);
}
};
struct foo
{
struct key_type
{
bool operator<(const key_type& other) const { return true; }
};
operator key_type() const { return key_type(); }
};
int main()
{
mutable_set<foo> s;
s.insert(foo());
}
(Note that #2 and #4 have been reversed.)
To add to the story very briefly:
Modifying set elements was always considered a squirreley thing to do, so
even VC9 had an undocumented and untested option called _HAS_IMMUTABLE_SETS
that defaulted to 0. (Don't try to use it! Read on.) While we were
rewriting the STL in VC10, I noticed this option and that C++0x mandated set
immutability, so I changed its default to 1 (leaving it as an escape hatch).
Then I discovered that it didn't actually work - in certain cases, it
allowed set elements to be modified anyways. By this point, after seeing
several instances of people modifying set elements throughout VS's codebase,
I had become completely opposed to modifying set elements (just like C++0x),
and I had encountered an ironclad solution to the problem (mentioned in the
SCARY iterator proposal). So I made set's iterator be the same type as
const_iterator, and removed the _HAS_IMMUTABLE_SETS escape hatch.
STL
"Leigh Johnston" <le...@i42.co.uk> wrote in message
news:%23$$1GM3gK...@TK2MSFTNGP06.phx.gbl...
Stephen,
So it's not Dinkum in VC10 anymore?
Dinkumware does most of the heavy lifting - I review their changes and fix
bugs. This was one of the bugs that I fixed, hence my use of the word "I"
in this story.
STL
"sasha" <a...@fox.net> wrote in message
news:%23Yno5pX...@TK2MSFTNGP06.phx.gbl...
> Dinkumware does most of the heavy lifting - I review their changes and
> fix bugs. This was one of the bugs that I fixed, hence my use of the
> word "I" in this story.
>
OK understood, thanks for clearing up the confusion. Btw, I enjoyed
reading your blog on the rvalue references and experimenting with them.
Hope you don't mind that I was using a different compiler for that :)