Discussion:
std::set and std::multiset element mutability
(too old to reply)
Leigh Johnston
2009-12-23 01:55:15 UTC
Permalink
VC9 allows you to modify a std::set and a std::multiset's elements. This
seems to be forbidden by the c++0x standard, so is this being fixed in VC10
or left as it is in order not to break software which is c++03 standard's
compliant (debatable) but not c++0x standard's compliant?

/Leigh
David Wilkinson
2009-12-23 12:39:53 UTC
Permalink
Post by Leigh Johnston
VC9 allows you to modify a std::set and a std::multiset's elements.
This seems to be forbidden by the c++0x standard, so is this being fixed
in VC10 or left as it is in order not to break software which is c++03
standard's compliant (debatable) but not c++0x standard's compliant?
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
Leigh Johnston
2009-12-24 16:57:17 UTC
Permalink
Post by David Wilkinson
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).
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());
}
Leigh Johnston
2009-12-25 17:10:02 UTC
Permalink
Take a look at http://i42.co.uk/stuff/mutable_set.htm if you like for my
full take on this.

/Leigh
Stephan T. Lavavej [MSFT]
2010-01-04 19:15:05 UTC
Permalink
I built a time machine, so I answered your question over half a year ago:

http://blogs.msdn.com/vcblog/archive/2009/05/25/stl-breaking-changes-in-visual-studio-2010-beta-1.aspx

(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
Post by Leigh Johnston
VC9 allows you to modify a std::set and a std::multiset's elements. This
seems to be forbidden by the c++0x standard, so is this being fixed in
VC10 or left as it is in order not to break software which is c++03
standard's compliant (debatable) but not c++0x standard's compliant?
/Leigh
sasha
2010-01-04 20:14:07 UTC
Permalink
on.) While we were rewriting the STL in VC10, I noticed this option and
Stephen,

So it's not Dinkum in VC10 anymore?
Stephan T. Lavavej [MSFT]
2010-01-04 21:40:47 UTC
Permalink
Actually, we're working with Dinkumware closer than ever before. During
VC8, Microsoft's sources diverged significantly from Dinkumware's master
sources. In VC10 we got back in sync. This, combined with the introduction
of many C++0x features like rvalue references, looks like a major rewrite of
the STL as far as our users are concerned (and it certainly felt like a
major rewrite to us).

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
Post by sasha
on.) While we were rewriting the STL in VC10, I noticed this option and
Stephen,
So it's not Dinkum in VC10 anymore?
sasha
2010-01-04 21:52:10 UTC
Permalink
Post by Stephan T. Lavavej [MSFT]
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 :)
Loading...