Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

why no const operator[] for map?

1 view
Skip to first unread message

Robert Klemme

unread,
May 10, 2000, 3:00:00 AM5/10/00
to
this is really a question for comp.std.c++.

robert


Pete Isensee schrieb:
>
> In early versions of the draft standard, map<T,K> included both:
>
> T& operator[]( const K& ); // this one made it into the standard
> const T& operator[]( const K& ) const; // this one did not...
>
> In the final standard, only the non-const version is included. This version
> will insert an object into the map if a matching object doesn't exist. Can
> anyone comment on why the committee chose not to include the const version,
> as in vector and deque? Seems like accessing a non-existent element could
> have been "undefined behavior" or even better as an exception.
>
> [ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
> [ about comp.lang.c++.moderated. First time posters: do this! ]

--
Robert Klemme
Software Engineer
-------------------------------------------------------------
myview technologies GmbH & Co. KG
Riemekestraße 160 ~ D-33106 Paderborn ~ Germany
E-Mail: mailto:robert...@myview.de
Telefon: +49/5251/69090-321 ~ Fax: +49/5251/69090-399
-------------------------------------------------------------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]

Pete Isensee

unread,
May 10, 2000, 3:00:00 AM5/10/00
to
In early versions of the draft standard, map<T,K> included both:

T& operator[]( const K& ); // this one made it into the standard
const T& operator[]( const K& ) const; // this one did not...

In the final standard, only the non-const version is included. This version

will insert an object into the map if a matching object doesn't exist. I'm
trying to understand why the committe chose not to include the const
version, as in vector and deque? I'm sure there's a good reason, but it's
not immediately obvious to me.


---

Dave Abrahams

unread,
May 13, 2000, 3:00:00 AM5/13/00
to
in article 8f9os3$dnr$1...@brokaw.wa.com, Pete Isensee at pe...@emeraldcity.com
wrote on 5/10/00 8:01 PM:

> In early versions of the draft standard, map<T,K> included both:
>
> T& operator[]( const K& ); // this one made it into the standard
> const T& operator[]( const K& ) const; // this one did not...
>
> In the final standard, only the non-const version is included. This version
> will insert an object into the map if a matching object doesn't exist. I'm
> trying to understand why the committe chose not to include the const
> version, as in vector and deque? I'm sure there's a good reason, but it's
> not immediately obvious to me.

Because of the way a map must be implemented internally, there is no way to
form a reference to a (key, value) pair which isn't already in the map
without modifying the map (i.e. by inserting a node).

On the other hand, it would have been possible, and useful IMO, to have the
const version of operator[] throw an exception if the key is not found.

I think the reason that this didn't make it into the standard is probably
that nobody (or not enough people) thought of it in time.

-Dave

Fergus Henderson

unread,
May 17, 2000, 3:00:00 AM5/17/00
to
Dave Abrahams <abra...@mediaone.net> writes:

>Pete Isensee at pe...@emeraldcity.com >wrote on 5/10/00 8:01 PM:
>
>> In early versions of the draft standard, map<T,K> included both:
>>
>> T& operator[]( const K& ); // this one made it into the standard
>> const T& operator[]( const K& ) const; // this one did not...
>>
>> In the final standard, only the non-const version is included. This version
>> will insert an object into the map if a matching object doesn't exist. I'm
>> trying to understand why the committe chose not to include the const
>> version, as in vector and deque? I'm sure there's a good reason, but it's
>> not immediately obvious to me.
>
>Because of the way a map must be implemented internally, there is no way to
>form a reference to a (key, value) pair which isn't already in the map
>without modifying the map (i.e. by inserting a node).
>
>On the other hand, it would have been possible, and useful IMO, to have the
>const version of operator[] throw an exception if the key is not found.
>
>I think the reason that this didn't make it into the standard is probably
>that nobody (or not enough people) thought of it in time.

I think people objected, or would have objected, to a function
behaving differently (inserting a new element or throwing an
exception) depending only on whether an object was `const' or not.
`const' is supposed to be about static type safety; in the absence of
casts and other loopholes, adding `const' shouldn't lead to errors
at run-time.

--
Fergus Henderson <f...@cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger f...@128.250.37.3 | -- the last words of T. S. Garp.

Rob Stewart

unread,
May 17, 2000, 3:00:00 AM5/17/00
to
Fergus Henderson wrote:
>
> Dave Abrahams <abra...@mediaone.net> writes:
>
> >Pete Isensee at pe...@emeraldcity.com >wrote on 5/10/00 8:01 PM:
> >
> >> In early versions of the draft standard, map<T,K> included both:
> >>
> >> T& operator[]( const K& ); // this one made it into the standard
> >> const T& operator[]( const K& ) const; // this one did not...
> >>
> >> In the final standard, only the non-const version is included. This version
> >
> >On the other hand, it would have been possible, and useful IMO, to have the
> >const version of operator[] throw an exception if the key is not found.
> >
> >I think the reason that this didn't make it into the standard is probably
> >that nobody (or not enough people) thought of it in time.
>
> I think people objected, or would have objected, to a function
> behaving differently (inserting a new element or throwing an
> exception) depending only on whether an object was `const' or not.
> `const' is supposed to be about static type safety; in the absence of
> casts and other loopholes, adding `const' shouldn't lead to errors
> at run-time.

Do you suppose it would have caused problems if it returned T()?
The function could even have a local static T, default
constructed, then return that by const reference, eliminating the
copy.

--
Robert Stewart | rob-at-giage-dot-com
Software Engineer | using std::disclaimer;
Giage, Inc. | http://www.giage.com

Bill Wade

unread,
May 24, 2000, 3:00:00 AM5/24/00
to

"Rob Stewart" <donot...@giage.com> wrote in message
news:3921AEDA...@giage.com...

>
> Do you suppose it would have caused problems if it returned T()?
> The function could even have a local static T, default
> constructed, then return that by const reference, eliminating the
> copy.

Map inserts don't affect existing references. Consider what your suggestion
does to the following code:

const T* p = &mymap[x]; // In a const context
mymap[x] = y; // In a non-const context
assert(*p == y); // In any context.

Rob Stewart

unread,
May 25, 2000, 3:00:00 AM5/25/00
to
Bill Wade wrote:
>
> "Rob Stewart" <donot...@giage.com> wrote in message
> news:3921AEDA...@giage.com...
> >
> > Do you suppose it would have caused problems if it returned T()?
> > The function could even have a local static T, default
> > constructed, then return that by const reference, eliminating the
> > copy.
>
> Map inserts don't affect existing references. Consider what your suggestion
> does to the following code:
>
> const T* p = &mymap[x]; // In a const context
> mymap[x] = y; // In a non-const context
> assert(*p == y); // In any context.

I understand your point, but if operator [](Key const &) const
were defined to return a T() (or a reference to one), then your
assertion would be defined to fail. There's nothing undefined,
just an indication that the programmer didn't understand what the
operator returned. IOW, I don't think that's a likely scenario
and it can be called incorrect usage.

--
Robert Stewart | rob-at-giage-dot-com
Software Engineer | using std::disclaimer;
Giage, Inc. | http://www.giage.com

---

John Potter

unread,
May 25, 2000, 3:00:00 AM5/25/00
to
On Thu, 25 May 2000 02:24:08 CST, Rob Stewart <donot...@giage.com>
wrote:

> Bill Wade wrote:
> >
> > "Rob Stewart" <donot...@giage.com> wrote in message
> > news:3921AEDA...@giage.com...
> > >
> > > Do you suppose it would have caused problems if it returned T()?
> > > The function could even have a local static T, default
> > > constructed, then return that by const reference, eliminating the
> > > copy.
> >
> > Map inserts don't affect existing references. Consider what your suggestion
> > does to the following code:
> >
> > const T* p = &mymap[x]; // In a const context
> > mymap[x] = y; // In a non-const context
> > assert(*p == y); // In any context.
>
> I understand your point, but if operator [](Key const &) const
> were defined to return a T() (or a reference to one), then your
> assertion would be defined to fail. There's nothing undefined,
> just an indication that the programmer didn't understand what the
> operator returned. IOW, I don't think that's a likely scenario
> and it can be called incorrect usage.

This is comp.std.c++ and Bill is one of the best at showing that
something is not consistent with the standard. The standard
states that references into a map shall not be invalidated by
an insert. That means that the map implementation must be such
that they are not invalidated. It is impossible to add an
operator[] const which returns a const reference to a static or
a value without making other major changes to the standard. The
standard never assures you that conforming code is valid only if
you understand the way it was intended to be used. Note that if
the element were in the map, the const reference would remain
valid through inserts; however, any attempt to fake an element would
result in a reference which could be invalidated.

Operator[] const can't throw because that would be very strange. It
can't fake an element because the reference could be invalidated. It
can't add the element because that is not consistent with const. Maybe
the committee knew what they were doing when they left it out.

John

Rob Stewart

unread,
May 26, 2000, 3:00:00 AM5/26/00
to
John Potter wrote:
>
> On Thu, 25 May 2000 02:24:08 CST, Rob Stewart <donot...@giage.com>
> wrote:
>
> > I understand your point, but if operator [](Key const &) const
> > were defined to return a T() (or a reference to one), then your
> > assertion would be defined to fail. There's nothing undefined,
> > just an indication that the programmer didn't understand what the
> > operator returned. IOW, I don't think that's a likely scenario
> > and it can be called incorrect usage.
>
> This is comp.std.c++ and Bill is one of the best at showing that
> something is not consistent with the standard. The standard

Irrelevant.

> states that references into a map shall not be invalidated by
> an insert. That means that the map implementation must be such
> that they are not invalidated. It is impossible to add an

That is how std::map is now defined. With the addition of a new
operator [](), the definition could be changed. If the
definition changes, the standard changes. Whether that change is
welcome, useful, and reasonable is quite separate.

> operator[] const which returns a const reference to a static or
> a value without making other major changes to the standard. The

Perhaps you're right, but I don't see what major changes are
necessary.

> standard never assures you that conforming code is valid only if
> you understand the way it was intended to be used. Note that if

The standard defines conformance. If the standard says that
there's a const subscript operator in std::map with certain
behavior and consequences, and you try to do something outside
those delineated boundaries, then you have non-conforming code.
Thus, *if* the standard were to mandate such an operator *and* it
documented the behavior and consequences of it, it would thus
mandate proper usage.

> the element were in the map, the const reference would remain
> valid through inserts; however, any attempt to fake an element would
> result in a reference which could be invalidated.

If you retained a reference to the temporary returned from such
an operator, or to the reference returned by such an operator (if
it were defined to return a reference), that reference, by
definition will not match the reference returned by the map once
an entry with that key is inserted. If that behavior were to
prove unusable for some purpose, you'd avoid code that trips over
it.

--
Robert Stewart | rob-at-giage-dot-com
Software Engineer | using std::disclaimer;
Giage, Inc. | http://www.giage.com

---

Peter Dimov

unread,
May 26, 2000, 3:00:00 AM5/26/00
to
John Potter <jpo...@falcon.lhup.edu> wrote in message
news:392cb26a...@news.csrlink.net...

[...]

> Operator[] const can't throw because that would be very strange. It
> can't fake an element because the reference could be invalidated. It
> can't add the element because that is not consistent with const. Maybe
> the committee knew what they were doing when they left it out.

Operator[] const can fake an element. There is no way to get a reference to
a const map element - const iterators are allowed to return rvalues.

--
Peter Dimov
Multi Media Ltd.

John Potter

unread,
May 27, 2000, 3:00:00 AM5/27/00
to
On Fri, 26 May 2000 23:03:12 CST, "Peter Dimov" <pdi...@mmltd.net>
wrote:

> John Potter <jpo...@falcon.lhup.edu> wrote in message
> news:392cb26a...@news.csrlink.net...
>

> > Operator[] const can't throw because that would be very strange. It
> > can't fake an element because the reference could be invalidated. It
> > can't add the element because that is not consistent with const. Maybe
> > the committee knew what they were doing when they left it out.
>
> Operator[] const can fake an element. There is no way to get a reference to
> a const map element - const iterators are allowed to return rvalues.

Great, problem solved. Now could you educate me? I can't seem to find
that in the standard or issues list. All I find is that the difference
between mutable and constant iterators is that the first returns a
reference while the second returns a const reference. The same for
optional sequence requirements, operator[] returns a reference or a
const reference. Once I have your reference (hope its not an rvalue :),
it will clear up a lot of other things.

John

pdi...@my-deja.com

unread,
May 30, 2000, 3:00:00 AM5/30/00
to
In article <392e8a1a...@news.csrlink.net>,

jpo...@falcon.lhup.edu (John Potter) wrote:
> On Fri, 26 May 2000 23:03:12 CST, "Peter Dimov" <pdi...@mmltd.net>
> wrote:
>
> > Operator[] const can fake an element. There is no way to get a
reference to
> > a const map element - const iterators are allowed to return rvalues.
>
> Great, problem solved. Now could you educate me? I can't seem to
find
> that in the standard or issues list. All I find is that the
difference
> between mutable and constant iterators is that the first returns a
> reference while the second returns a const reference. The same for
> optional sequence requirements, operator[] returns a reference or a
> const reference. Once I have your reference (hope its not an
rvalue :),
> it will clear up a lot of other things.

24.1/4 states that "the result of the expression *i (for constant
iterator i) cannot be used in an expression where an lvalue is
required."

As for operator[] on sequences, I don't think that this applies to
std::map.

--
Peter Dimov
Multi Media Ltd.


Sent via Deja.com http://www.deja.com/
Before you buy.

A Robbie

unread,
Jun 22, 2000, 3:00:00 AM6/22/00
to
In article <8f9os3$dnr$1...@brokaw.wa.com>, "Pete Isensee"
<pe...@emeraldcity.com> wrote:

> In early versions of the draft standard, map<T,K> included both:
>
> T& operator[]( const K& ); // this one made it into the standard
> const T& operator[]( const K& ) const; // this one did not...
>
> In the final standard, only the non-const version is included. This version

> will insert an object into the map if a matching object doesn't exist. I'm
> trying to understand why the committe chose not to include the const
> version, as in vector and deque? I'm sure there's a good reason, but it's
> not immediately obvious to me.

You might like to browse deja news on this subject -- it has been bitched
about for some time. I agree with you totally in that it is a very strange
and unusual decision given how the other containers work. ISTR that it was
justified with a 'language X does it this way, and it lets them write this
piece of code in Y lines!' type of argument, but that may not have been the
reasoning of the committe -- which in any case moves in mysterious ways.

Regards,
Andrew

Andrew J Robb

unread,
Oct 14, 2000, 11:37:24 PM10/14/00
to
Pete Isensee wrote:

> In early versions of the draft standard, map<T,K> included both:
>
> T& operator[]( const K& ); // this one made it into the standard
> const T& operator[]( const K& ) const; // this one did not...
>
> In the final standard, only the non-const version is included. This version
> will insert an object into the map if a matching object doesn't exist. I'm
> trying to understand why the committe chose not to include the const
> version, as in vector and deque? I'm sure there's a good reason, but it's
> not immediately obvious to me.
>

> ---
> [ comp.std.c++ is moderated. To submit articles, try just posting with ]
> [ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
> [ --- Please see the FAQ before posting. --- ]
> [ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html ]

As you state, map::operator[] will modify the map if there is no match.
Therefore it cannot apply to const map.

I have defined a const object operator[] in a derived class, which throws an
exception if there is no match.

Maybe the standards commitee could not agree on the "correct" behavior for the
const map's operator[]???

---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]

[ FAQ: http://www.research.att.com/~austern/csc/faq.html ]
[ Note that the FAQ URL has changed! Please update your bookmarks. ]

James Dennett

unread,
Oct 15, 2000, 3:00:00 AM10/15/00
to
Andrew J Robb wrote:
>
> Pete Isensee wrote:
>
> > In early versions of the draft standard, map<T,K> included both:
> >
> > T& operator[]( const K& ); // this one made it into the standard
> > const T& operator[]( const K& ) const; // this one did not...
> >
> > In the final standard, only the non-const version is included. This version
> > will insert an object into the map if a matching object doesn't exist. I'm
> > trying to understand why the committe chose not to include the const
> > version, as in vector and deque? I'm sure there's a good reason, but it's
> > not immediately obvious to me.
> >
> As you state, map::operator[] will modify the map if there is no match.
> Therefore it cannot apply to const map.
>
> I have defined a const object operator[] in a derived class, which throws an
> exception if there is no match.
>
> Maybe the standards commitee could not agree on the "correct" behavior for the
> const map's operator[]???

I think, rather, that most C++ users agree that foo::bah() and
foo::bah() const
should differ only in performance. Otherwise code is too fragile; a
well-meaning
addition of const to a variable could silently cause code to fail if the
const
operator threw an exception instead of modifying the object concerned.

AFAIK, the Standard is consistent in making the behaviour of const
methods the
same as that of non-const methods (except in regard to const
qualifications!),
so the lack of an operator[] on map is quite reasonable.

-- James Dennett <jden...@acm.org>

0 new messages