From: Leigh Johnston on

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

From: David Wilkinson on
Leigh Johnston wrote:
>
> 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
From: Leigh Johnston on
>
> 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());
}


From: Leigh Johnston on
Take a look at http://i42.co.uk/stuff/mutable_set.htm if you like for my
full take on this.

/Leigh

From: Stephan T. Lavavej [MSFT] on
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

"Leigh Johnston" <leigh(a)i42.co.uk> wrote in message
news:%23$$1GM3gKHA.5520(a)TK2MSFTNGP06.phx.gbl...
>
> 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