Topic: Is there a proposal to fix the operator[] (rvalue/lvalue issues)??


Author: david.thompson1@worldnet.att.net (Dave Thompson)
Date: Mon, 11 Sep 2006 04:42:02 GMT
Raw View
On Wed, 30 Aug 2006 11:28:51 CST, "kanze" <kanze@gabi-soft.fr> wrote:

> Dave Harris wrote:

> > Associative arrays are found in lots of languages, and where
> > possible I can't think of a language that doesn't provide them
> > with the same syntax as hardware arrays.
>
> Lisp?  The only other languages I know which provide them are
> AWK and Java.  (I know other langauges provide them, but they
> aren't languages I know.)  I don't think AWK is really relevant,
> for the reasons I mentionned before.  <snip>

Perl has $ array [ number ] and $ hash { string }
and autoextends/autocreates respectively,
though you can avoid that by explicitly checking first
  integer > $#array || integer < 0
  exists $hash{key}

For array it also has {push,pop}_{back,front} but under slight less
obvious names, with automatic reorigin in the _front cases.

- David.Thompson1 at worldnet.att.net

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





Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 31 Aug 2006 19:50:21 GMT
Raw View
kanze@gabi-soft.fr (kanze) wrote (abridged):
> > > What is your abstraction for an "array"?
>
> > Something that maps small non-negative integers to some other
> > kind of object, that happens to have an efficient
> > implementation in hardware.
>
> That last criteria leaves out std::map:-).

Because I thought by "array" you mean the feature found in C.


> The idea that one can iterate through an array by incrementing the
> index seems pretty fundamental to me, and that seems to strongly
> imply a numeric (or even integral) type.

Ah; I hadn't appreciated that that was what you meant. (I know you said
"conceptually", but I didn't know which concept you had in mind.)

Whether the index can be incremented is surely a feature of the index. The
accessing operation does not logically depend on it. The accessing
operation is basically, "given a (run-time) key, return the corresponding
value", which is really rather general. It is, or should be, the same
operation whether found in map or array. (Unfortunately std::map gets it
wrong.)

Which isn't to say that maps and arrays are the same thing. The iteration
feature is a way to distinguish them. However, it's part of the total
array package, rather than having to do with accessing specifically, so it
is not a reason to use different syntax for the access operator.

All in my view, of course.

-- Dave Harris, Nottingham, UK.

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





Author: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 29 Aug 2006 10:39:50 CST
Raw View
kanze@gabi-soft.fr (kanze) wrote (abridged):
> What is your abstraction for an "array"?

Something that maps small non-negative integers to some other kind of
object, that happens to have an efficient implementation in hardware.


> IMHO, it doesn't really fit in C++, because in C++, arrays
> are conceptually contiguous blocks of elements indexed by a
> small non-negative integer.

That's why I said a std::map was generalised from that concept. Contiguous
memory is a special case implementation. I don't see any need to restrict
operator[] to that implementation. To do so would be to remove much of the
point of operator overloading.

Even in C I would not be too bothered about whether the memory was
contiguous:
    int array[10][[5];
    int *raggedArray[10]; // ... initialise...
    array[2][3] = 1;
    raggedArray[2][3] = 2;

Here array and raggedArray are different implementations of the same
concept, one using contiguous memory and one not, with both using the same
syntax.

Do you think it is wrong to use operator+() for adding matrices? After
all, a matrix will be nothing like the built-in arithmetic types. Matrices
may not use contiguous memory either.


> The situation in AWK is not comparable: there are no integral types,
> to begin with (and anytime you use a name, the corresponding object gets
> created).

Your parenthetical remark is why the create-if-not-present semantics fits
in AWK, and I agree that doesn't fit the same way in C++, at least as the
default. So here I am just talking about operator[] for accessing without
insertion. (Just to clarify.)

Associative arrays are found in lots of languages, and where possible I
can't think of a language that doesn't provide them with the same syntax
as hardware arrays. I still don't really understand why you think their
syntax should differ.


> There are cases where you do want to insert if the value isn't
> already there.  Maybe we need a function name for that as well.

If we go with "at_else" for the default value version, "at_else_insert"
might do for the inserting version. The clumsiness of the name reflects
the mixed-up nature of the function.

-- Dave Harris, Nottingham, UK.

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





Author: "kanze" <kanze@gabi-soft.fr>
Date: Wed, 30 Aug 2006 11:28:51 CST
Raw View
Dave Harris wrote:
> kanze@gabi-soft.fr (kanze) wrote (abridged):
> > What is your abstraction for an "array"?

> Something that maps small non-negative integers to some other
> kind of object, that happens to have an efficient
> implementation in hardware.

That last criteria leaves out std::map:-).

Seriously, I think that the real question does concern the type
of the index.  Or perhaps the operations allowed on it.

> > IMHO, it doesn't really fit in C++, because in C++, arrays
> > are conceptually contiguous blocks of elements indexed by a
> > small non-negative integer.

> That's why I said a std::map was generalised from that
> concept. Contiguous memory is a special case implementation.

Physically contiguous, yes.  Conceptually continuous, I'm less
sure.  The idea that one can iterate through an array by
incrementing the index seems pretty fundamental to me, and that
seems to strongly imply a numeric (or even integral) type.

> I don't see any need to restrict operator[] to that
> implementation. To do so would be to remove much of the point
> of operator overloading.

My choice of the word conceptually was very intentional.  It is
the operations that are available externally that interest me.
The fact that given an array[i], I can access the following
element with array[i+1], for example.

> Even in C I would not be too bothered about whether the memory
> was contiguous:
>     int array[10][[5];
>     int *raggedArray[10]; // ... initialise...
>     array[2][3] = 1;
>     raggedArray[2][3] = 2;

> Here array and raggedArray are different implementations of
> the same concept, one using contiguous memory and one not,
> with both using the same syntax.

I'm not sure what your point is here.  In C, you have an array
of arrays, or an array of pointers (to arrays).  In all cases,
the arrays themselves are contiguous.

This is NOT the abstraction in every language.  Still, in most
of the languages I know, if you have array[i], array[i+1] gives
the next element, supposing it exists.

> Do you think it is wrong to use operator+() for adding
> matrices?  After all, a matrix will be nothing like the
> built-in arithmetic types.  Matrices may not use contiguous
> memory either.

Good question.  I'm not familiar with numerics enough to be
aware of what would be appropriate.  I suspect that in this
case, we have the use of the same symbol outside of the language
which makes it appropriate.  And that if I were using matrices,
I'd be familiar enough with this notation to make it
appropriate.  The use of [] is, however, very much a C'ism; I
don't know of any domain where the literature makes use of these
characters in that way.

> Associative arrays are found in lots of languages, and where
> possible I can't think of a language that doesn't provide them
> with the same syntax as hardware arrays.

Lisp?  The only other languages I know which provide them are
AWK and Java.  (I know other langauges provide them, but they
aren't languages I know.)  I don't think AWK is really relevant,
for the reasons I mentionned before.  And I'm not sure that I'd
take a language as reference which requires writing a.add(b)
rather than a+b to add complex or BigDecimal.  So I'm back to
square one.

Some forms of operator overloading are indicutably "correct":
arithmetic operators for BigDecimal, for example.  Some are
almost certainly correct in the context of C++: unary * for a
smart pointer, or [] for array-like containers.  Some are
obviously abuse: I once saw an iterator that used unary + to
determine whether it was finished or not.  Somewhere between the
two extremes, however, is a gray zone where opinions will vary.
I would limit [] to array-like containers, and I'm pretty strict
as to what "array-like" means.  My own feeling is that for
something like map, it is pushing the limit, but I accept it if
others in the team want it (which I wouldn't do for a unary + to
indicate the end of iteration).  I'm not totally comfortable
with it, but I don't think the abuse is manifest enough to
really complain about.

> I still don't really understand why you think their syntax
> should differ.

Because incrementing the "index" won't give me the next element.

Also because there doesn't seem to be a total concensus as to
what it should do, if the element doesn't exist.  (I'd probablly
feel easier about it if it didn't insert, but still not 100%
comfortable.)

> > There are cases where you do want to insert if the value
> > isn't already there.  Maybe we need a function name for that
> > as well.

> If we go with "at_else" for the default value version,
> "at_else_insert" might do for the inserting version. The
> clumsiness of the name reflects the mixed-up nature of the
> function.

Agreed there.

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


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





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sat, 26 Aug 2006 15:29:29 CST
Raw View
spam@spamguard.com ("Gene Bushuyev") wrote (abridged):
> I don't really see the big problem here other than that operator[]
> doesn't fit the concept of associative containers, nor is it
> practically useful or desirable.

It was found very useful and desirable in other languages: for example,
Awk. It very much fits the concept of associative containers. A map is
conceptually a generalised array; an array for which the index need not be
a small integer. So certainly operator[] should be provided.

For me the only question is what it should do if the key is missing. In my
view, it should be undefined behaviour for both const and non-const
versions. This matches std::vector. There should also be map::at() which
throws. (And possibly a third function that returns a default value, which
should also be added to std::vector.)

The function which finds a key and returns its value if found, or inserts
a default value and returns that if not found, is also very useful. We
certainly don't want to write code like:

    if (myMap.contains( key ))
        myMap[key] += 1;
    else
        myMap.insert( make_pair( key, 1 ) );

which effectively does the look-up twice. We can avoid the double look-up
with code like:

   (*((myMap.insert(make_pair(key, 0))).first)).second += 1;

but this is pretty messy syntax for what ought to be a basic function. So
I think map should have a function to do this. It just shouldn't have been
called operator[].

-- Dave Harris, Nottingham, UK.

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





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sat, 26 Aug 2006 20:28:48 GMT
Raw View
jose.diego@gmail.com () wrote (abridged):
> I made the following function to access a map elements to simulate the
> operator[] in a const map
>
>  [snip get() function that returns a default value]
>
> If the std::map<>::operator[] could be used as an rvalue, it could have
> the above implementation
>
> What do you think?

I think it differs too much from operator[] to have that name. It's
result type is different, and it never inserts missing keys.

However, I agree it is a useful function. I would call it something like,
"at_if_absent", or "at_else". And I'd provide it for all the indexed
containers. For example:

    const value &at_else( const vector<value> &vec, size_t key,
            const value &ifAbsent=value() ) {
        return (key < vec.size()) ? vec[key] : ifAbsent;
    }

The non-const version makes sense, too, but is slightly problematic in C++
because we can't bind non-const references to temporary values. It would
still be useful with non-temporaries, eg:

    std::vector<int> counts(100);
    int missingCount = 0;

    for (int i = 0; i < 1000; ++i)
        at_else( counts, rand()/100, missingCount ) += 1;


-- Dave Harris, Nottingham, UK.

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





Author: "kanze" <kanze@gabi-soft.fr>
Date: Mon, 28 Aug 2006 09:08:03 CST
Raw View
Dave Harris wrote:
> spam@spamguard.com ("Gene Bushuyev") wrote (abridged):
> > I don't really see the big problem here other than that
> > operator[] doesn't fit the concept of associative
> > containers, nor is it practically useful or desirable.

> It was found very useful and desirable in other languages: for
> example, Awk. It very much fits the concept of associative
> containers. A map is conceptually a generalised array; an
> array for which the index need not be a small integer. So
> certainly operator[] should be provided.

I think you could argue it both ways.  What is your abstraction
for an "array"?  IMHO, it doesn't really fit in C++, because in
C++, arrays are conceptually contiguous blocks of elements
indexed by a small non-negative integer.  The situation in AWK
is not comparable: there are no integral types, to begin with
(and anytime you use a name, the corresponding object gets
created).

Of course, I tend to be a stickler with regards to operator
overloading, and its abuse.  My AssocArrayOf (hash table) does
have an operator[], because every users seems to want one.

> For me the only question is what it should do if the key is
> missing. In my view, it should be undefined behaviour for both
> const and non-const versions. This matches std::vector. There
> should also be map::at() which throws. (And possibly a third
> function that returns a default value, which should also be
> added to std::vector.)

That does sound like the most reasonable solution, if you accept
that it must be supported.  You might also add get(), which
returns a pointer to the element (and NULL if the element isn't
present).

There are cases where you do want to insert if the value isn't
already there.  Maybe we need a function name for that as well.

> The function which finds a key and returns its value if found,
> or inserts a default value and returns that if not found, is
> also very useful. We certainly don't want to write code like:

>     if (myMap.contains( key ))
>         myMap[key] += 1;
>     else
>         myMap.insert( make_pair( key, 1 ) );

> which effectively does the look-up twice.

That's an optimizing issue.  I've always designed my associative
containers so that multiple look-up on the same key was very
fast.

> We can avoid the double look-up with code like:

>    (*((myMap.insert(make_pair(key, 0))).first)).second += 1;

> but this is pretty messy syntax for what ought to be a basic
> function. So I think map should have a function to do this. It
> just shouldn't have been called operator[].

I agree, but I still haven't found a name which really works.

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


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





Author: spam@spamguard.com ("Gene Bushuyev")
Date: Wed, 23 Aug 2006 03:45:34 GMT
Raw View
"kanze" <kanze@gabi-soft.fr> wrote in message
news:1155910912.532657.322550@m73g2000cwd.googlegroups.com...
> jose.diego@gmail.com wrote:
[...]
> Which is correct.  In std::map, you cannot use operator[] on a
> const map.  And I agree that it is rather a pain.  In my own,
> pre-standard hash maps, operator[] returned a pointer, which was
> null if the element wasn't present.  Alternatively, you could
> use an exception.  Or even provide a contains function and make
> it a fatal error to use operator[] with a key where contains
> returns false.

You still can use an iterator returned by find(), etc. functions. It's kinda
pointer, right?
I don't really see the big problem here other than that operator[] doesn't fit
the concept of associative containers, nor is it practically useful or
desirable. The committee, I believe correctly, decided against operator[] for
lists, but for some strange reason they added it for maps where it makes even
less sense. If anything, my suggestion would be to deprecate operator[] for
associative containers.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

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





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Tue, 22 Aug 2006 23:57:43 CST
Raw View
"Gene Bushuyev" wrote:
> <jose.diego@gmail.com> wrote in message
> news:1155678420.260516.259860@74g2000cwt.googlegroups.com...
> >I made the following function to access a map elements to simulate the
> > operator[] in a const map
> >
> > template<typename MapType>
> > const MapType::value_type::second_type get(const MapType map, const
> > MapType::value_type::first_type value) {
> > MapType::const_iterator it = map.find(value);
> > if( it == map.end() ) return MapType::value_type::second_type();
> > return *it;
> > }
> >
> > If the std::map<>::operator[] could be used as an rvalue, it could have
> > the above implementation
> >
> > What do you think?
>
>
> Your solution is already problematic because it breaks the standardized
> behavior.

The "standardized" behavior - if std::string or std::vector is any kind
of example - is to implement both a non-const and const operator[]. By
implementing only a non-const operator[], std::map would appear to be
the exception.

> It's highly unlikely that the committee will choose to make changes
> that break a lot of code.

Adding a const version of a std::map's operator[] could not break any
existing code - since no existing code could be invoking operator[] on
a const std::map.

> On the other hand, no clear logic dictates whether a
> new element should or should not be added to the map or the exception should be
> thrown when operator [] is invoked for non-existing element.

You seem to be unaware that std::map already implements a non-const
operator[]. Its behavior is to insert a value when invoked with a key
not already present in the map. The question here is the best analagous
behavior were a non-const operator[] added to std::map.

> I personally would
> prefer exception, but in the final analysis it's not important. Using iterators
> is more logical with associative containers and doesn't have any of these
> problems, and that's what people are accustomed to doing - using find(),
> lower/upper_bound(), etc.

For programs that currently retrieve values by indexing a non-const
std::map - being able to access a const std::map in the same way does
seem useful. After all, most programmers expect the non-const and const
versions of an object to behave consistently.

Greg

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





Author: "kanze" <kanze@gabi-soft.fr>
Date: Wed, 23 Aug 2006 09:36:10 CST
Raw View
Greg Herlihy wrote:
> "Gene Bushuyev" wrote:
> > <jose.diego@gmail.com> wrote in message
> > news:1155678420.260516.259860@74g2000cwt.googlegroups.com...
> > >I made the following function to access a map elements to simulate the
> > > operator[] in a const map

> > > template<typename MapType>
> > > const MapType::value_type::second_type get(const MapType map, const
> > > MapType::value_type::first_type value) {
> > > MapType::const_iterator it = map.find(value);
> > > if( it == map.end() ) return MapType::value_type::second_type();
> > > return *it;
> > > }

> > > If the std::map<>::operator[] could be used as an rvalue,
> > > it could have the above implementation

> > > What do you think?

> > Your solution is already problematic because it breaks the
> > standardized behavior.

> The "standardized" behavior - if std::string or std::vector is
> any kind of example - is to implement both a non-const and
> const operator[]. By implementing only a non-const operator[],
> std::map would appear to be the exception.

The "standardized" behavior---if std::string, std::deque,
std::vector and T[] are any kind of example---is for operator[]
to take a unsigned integral type as parameter, and to return a
reference to the (n+1)'th element. std::map is definitly an
exception.

    [...]
> You seem to be unaware that std::map already implements a
> non-const operator[]. Its behavior is to insert a value when
> invoked with a key not already present in the map. The
> question here is the best analagous behavior were a non-const
> operator[] added to std::map.

Don't want to speak for Gene (we disagree often enough), but I
think his point is that there is no analagous behavior.

> > I personally would prefer exception, but in the final
> > analysis it's not important. Using iterators is more logical
> > with associative containers and doesn't have any of these
> > problems, and that's what people are accustomed to doing -
> > using find(), lower/upper_bound(), etc.

> For programs that currently retrieve values by indexing a
> non-const std::map - being able to access a const std::map in
> the same way does seem useful.

Except that the semantics of indexing in the current version of
std::map don't make sense for a const object.  This may be the
result of an abuse of operator overloading, but it's there, and
we have to live with it.  (If we based our specification on the
behavior of [] for vector, deque and built-in arrays, trying to
access an inexisting element would be undefined behavior.  And
we'd need some sort of function, say contains(), since size()
obviously wouldn't be the correct name in this case, to
determine beforehand whether the element was present.)

> After all, most programmers expect the non-const and const
> versions of an object to behave consistently.

There doesn't seem to be any consensus as to what the behavior
of [] on a map should be, so it's hard to say.  I would expect
that [] on a const and on a non-const map have the same
behavior, but then, I'd also expect undefined behavior if the
element wasn't present (and I'd expect the argument to be an
integral type, but that's another question).

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


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





Author: spam@spamguard.com ("Gene Bushuyev")
Date: Wed, 23 Aug 2006 15:54:32 GMT
Raw View
"Jens Theisen" <jth02@arcor.de> wrote in message
news:44eb8e1f$0$10159$9b4e6d93@newsspool2.arcor-online.net...
> Gene Bushuyev wrote:
>>>Please can you explain us how will my solution break "a lot of code"?
>>>Currently, STL DOES NOT HAVE operator[] for const maps :-)
>>
>> Are you forgetting about mutable keyword?
>
> What about it? Can you make an example?


The following standard conforming program would fail if the suggested changes
were implemented.

class A
{
    mutable std::map<int,int> m;
public:
    int f(int index) const { return m[index]; }
    bool found(int index) const { return m.count(index); }
};

int main()
{
    A a;
    std::cout << a.f(0);
    ASSERT(a.found(0));
}

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

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





Author: jth02@arcor.de (Jens Theisen)
Date: Wed, 23 Aug 2006 16:14:32 GMT
Raw View
Greg Herlihy wrote:
> The "standardized" behavior - if std::string or std::vector is any kind
> of example - is to implement both a non-const and const operator[]. By
> implementing only a non-const operator[], std::map would appear to be
> the exception.

The case of std::string is similar in that regard, since it's non-const
versions have different semantics (they invalidate iterators), and the
same goes for their begin/end functions.

Any C++ programmer will at some point stumble across this weird
difference in semantics (when I did, it took me a couple of hours to
track it down), and I'm glad std::map doesn't provide another instance
of such confusing behaviour.

I agree with you that it would make some expressions look nicer and I
also can't see how it would brake any code.

Jens

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





Author: "kanze" <kanze@gabi-soft.fr>
Date: Wed, 23 Aug 2006 11:16:14 CST
Raw View
"Gene Bushuyev" wrote:
> "kanze" <kanze@gabi-soft.fr> wrote in message
> news:1155910912.532657.322550@m73g2000cwd.googlegroups.com...
> > jose.diego@gmail.com wrote:
> [...]
> > Which is correct.  In std::map, you cannot use operator[] on
> > a const map.  And I agree that it is rather a pain.  In my
> > own, pre-standard hash maps, operator[] returned a pointer,
> > which was null if the element wasn't present.
> > Alternatively, you could use an exception.  Or even provide
> > a contains function and make it a fatal error to use
> > operator[] with a key where contains returns false.

> You still can use an iterator returned by find(), etc.
> functions. It's kinda pointer, right?

Not really a pointer, but very usable, agreed.

> I don't really see the big problem here other than that
> operator[] doesn't fit the concept of associative containers,
> nor is it practically useful or desirable. The committee, I
> believe correctly, decided against operator[] for lists, but
> for some strange reason they added it for maps where it makes
> even less sense. If anything, my suggestion would be to
> deprecate operator[] for associative containers.

I think that there is a very strong argument that operator[] on
a map is an abuse of operator overloading.  Still, people seem
to insist on having it, even if there doesn't seem to be any
real consensus as to what it should mean.  (Which, IMHO, is
proof that it is operator overloading abuse.)

I'd say the same thing is true concerning operator[] on string,
unless it actually did return the n'th character (as a string,
since a single character may occupy several bytes), and not the
n'th byte; and even operator+, which to me suggests commutivity.
But some "abuse" has become so widely accepted that you can't
avoid it---I added an operator[] to my pre-standard string class
because I got tired of trying to explain why it wasn't there.

So I think we're stuck with it.

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


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





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Wed, 23 Aug 2006 11:27:52 CST
Raw View
"Gene Bushuyev" wrote:
>
> The following standard conforming program would fail if the suggested changes
> were implemented.
>
> class A
> {
>     mutable std::map<int,int> m;
> public:
>     int f(int index) const { return m[index]; }
>     bool found(int index) const { return m.count(index); }
> };
>
> int main()
> {
>     A a;
>     std::cout << a.f(0);
>     ASSERT(a.found(0));
> }

Would it? Given that map is mutable wouldn't the non-const overload
take precedence even though the member function is const?

Actually, it is the above behaviour I am concerned about where the user
does not expect the element to have been added by calling a const
method. At present, it is the fault of the writer of the class who
knows that operator[] is a non-const operator and is choosing to call
it here knowing what will happen.

The more likely error to occur could happen when iterating through the
map. Now if your map is from K to shared_ptr<T> where K is a key-type,
and on iterating you call a method of T, woe to you if your map
suddenly contains empty shared_ptrs. You'll have your work cut out
working out where those came from.

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





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Wed, 23 Aug 2006 12:07:39 CST
Raw View
Greg Herlihy wrote:
> For programs that currently retrieve values by indexing a non-const
> std::map - being able to access a const std::map in the same way does
> seem useful. After all, most programmers expect the non-const and const
> versions of an object to behave consistently.
>
but they wouldn't act consistently. When indexing a non-const map it
will insert an element where it doesn't exist, and you say it would not
do that when the map is const.

Users would write code to retrieve the values from a map, thinking they
are not modifying the map. The code would work, after all, with a
const-map but because it so happens that the map is non-const, it would
behave differently and insert elements.

Users would get used to using operator[] for lookup. Particularly as
users will be using shared_ptr<T> as the second (value) type in the map
and will know that none of the genuine elements contain empty
shared-pointers so when they retrieve one they will use that to mean
"does not exist".

Of course, if it adds an element, it will err silently, at this point.
It won't tell you it inserted an element and will appear to work
properly. And will continue to work properly while you are looking up
with operator[] because the element will not appear to have been added.

Then you call another function that iterates through the map and
suddenly comes across this element, calls a method that dereferences
the empty pointer and blows up.
Hard bug to find.

And just in case you think this won't happen, there are many times that
someone forgetrs to make a method const, and furthermore, there will be
instances where the map is mutable because lazy-evaluation is used. So
if the map is mutable the non-const overload will be used even when the
function is const. I know this could happen now anyway, but it is less
likely because users don't normally use operator[] for lookup.

Yes, we are protecting against poor programming here, but I don't see
the harm in doing that. The purpose of interfaces is to make life
easier for the programmer. An at() method would therefore be ideal. It
could even come with an extra flag parameter that can indicate whether
to throw or not on not-found. I think the default should be not to
throw (even though the normal behaviour of at() is to throw on
bounds-errors, but this is not a bounds-error because maps are
unbounded). My own functions that perform this kind of thing (actually
checked_inserter) not only has the option to throw, but you may supply
a method to print the key which by default is streaming but if the key
is not streamable you may pass in an alternative. (Actually you pass in
an operation to convert the key to something that is streamable. By
default it is a no-op convert).

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





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Thu, 24 Aug 2006 09:57:37 CST
Raw View
Greg Herlihy wrote:
>
> How could inserting a value for a missing key be unintentional in this
> situation?

The way you write the statement looks like you are only reading. It
doesn't look like you are modifying anything.

I'm going to assume that I have map< K, shared_ptr<T> > as my map type.
So the statement might look something like:

shared_ptr< T > ptr = myMap[ k ];

Now it doesn't look from that statement like I've modified myMap. It's
also the case that you can't do any useful writing with that statement.
If you want to use lazy-evaluation here you need to do:

shared_ptr< T > & ptr = myMap[ k ];

then if ptr is empty you retrieve its value from wherever (the more
expensive action than looking in the map) and call reset() on the
pointer. The gain here is that you have only had to locate the key on
the map once.

> The programmer must be expecting the key to be present in
> the std::map, so how could finding the key in the std::map as expected
> be an error?

No, the programmer in the original example is not intending to change
the map at all. He wants to get a shared_ptr<T> if the key exists, a
null shared_ptr if not.

>std::map's operator[] today returns exactly what the
> programmer asks for - and it can do no more than that. Of course it's
> possible to ask for things that one does not actually want.

Here it does return exactly what the programmer wants. But it also has
a nasty side-effect, which won't show up until later.

>But the Standard Library is not in a position to intuit the programmer's actual
> intentions.

No, but the Standard Library should protect the programmer's intuit by
not using notation that normally means one thing and here means
something different. With all other collections, if I call operator[]
it doesn't modify the collection. It may return me a non-const
reference to something but unless I write to it, nothing will have
changed at all.

Now we can't change the standard library as it is, albeit that the
notation is possibly flawed, because it will break existing code. But
we can discourage using operator[] for read operations by not providing
a const overload, particularly that the const overload will work
differently from the non-const overload even if you don't write to it.

> In one sense, accessing a std::map exclusively with operator[] makes it
> seem as if the map were fully-populated; every key succeeds in
> returning (at least a default) value. So whether or not those default
> values are actually stored in the map - or whether they might exist as
> "virtual" entries (as they would in a const std::map) - is likely to
> make little difference to any program using a std::map in this way.

As long as they never do anything other than attempt to read entries
with operator[] and write entries then they'll be fine. But what if
they want to iterate through the map? Then you'd have to check all
those pointers for null-ness before calling a method on them. You'll
probably forget - and the program will crash,. Even if you remember,
it's an overhead. In fact it's an overhead already because as the map
grows, lookup time grows, even if it is only logarithmically.

> Lastly, it is the case today that any C++ programmer under the
> impression that std::map has a const operator[] - has no chance of ever
> being right.

Assuming their methods are const-correct they'll get a compiler error.
If the map is mutable, oh well, yes, then they'll get into trouble
using operator[] for reading.

> At least if std::map did have a const operator[], then
> that same programmer would at least have a chance of being correct -
> occasionally.

No existing code would break and using operator[] when the map really
is const would not break anything either. But as programmers got used
to using operator[] for read operations, more bugs would creep in as
they would start using it on the wrong occasions more often.

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





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Thu, 24 Aug 2006 11:16:11 CST
Raw View
Jens Theisen wrote:
> Greg Herlihy wrote:
> > The "standardized" behavior - if std::string or std::vector is any kind
> > of example - is to implement both a non-const and const operator[]. By
> > implementing only a non-const operator[], std::map would appear to be
> > the exception.
>
> The case of std::string is similar in that regard, since it's non-const
> versions have different semantics (they invalidate iterators), and the
> same goes for their begin/end functions.

The non-const version of std::string's operator[] is not allowed to
invalidate the string's iterators [   21.3/6] - though it can certainly
be used to alter the string's contents:

    std::string s("abcd");

    s[0] = '1'; // s is now "1bcd"

> Any C++ programmer will at some point stumble across this weird
> difference in semantics (when I did, it took me a couple of hours to
> track it down), and I'm glad std::map doesn't provide another instance
> of such confusing behaviour.

It's not confusing at all. Programmers expect the index operator to be
able to perform two operations: first is to change the contents of a
non-const container (as shown above) and second is to access the
contents of a const container like so:

    const std::string s("abcd");

    char c = s[0]; // c is now 'a'

Unless both non-const and const versions of operator[] are implemented,
it is not possible to fulfill both expectations.

Greg


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





Author: "Joe" <jgreer@nsisoftware.com>
Date: Thu, 24 Aug 2006 12:59:04 CST
Raw View
It sounds like what folks want is a sparse array like thing.  I think
that is a little different than a map, but I am sure that map
understands [] precisely so that it can be used like that.  I don't a
map creating a null pointer for you, so the const version should
probably throw or be disallowed.  I also think that there is a place
for a sparse_array class that can return a default constructed item if
the key doesn't exist.

joe

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





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Thu, 24 Aug 2006 19:56:40 CST
Raw View
Greg Herlihy wrote:
>
> It's not confusing at all. Programmers expect the index operator to be
> able to perform two operations: first is to change the contents of a
> non-const container (as shown above) and second is to access the
> contents of a const container like so:
>
>     const std::string s("abcd");
>
>     char c = s[0]; // c is now 'a'
>
> Unless both non-const and const versions of operator[] are implemented,
> it is not possible to fulfill both expectations.

but here is where there is a major difference with associate
containers. Although in other containers you can use operator[] to
modify an entry, it never modifies the layout/size of the container. In
your example, s[0] must exist for me to write to it. It may be
uninitialised, but it must exist. If it doesn't exist, it is undefined
behaviour, whether I try reading it or writing it. (Actually I have
classes where I overload operator[] to return a "null" value when
non-existent and never be an invalid action).

If I call char c = s[0] on a string the same thing will happen
regardless of whether s is const or not. If I call c = s[4] and s is
"abcd" then I am reading out of bounds. I may end up with the
null-character but it's not safe to assume that. It won't silently
insert a null in position 4 and change the string size to 5.

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





Author: "kanze" <kanze@gabi-soft.fr>
Date: Fri, 25 Aug 2006 10:02:53 CST
Raw View
Greg Herlihy wrote:
> Jens Theisen wrote:
> > Greg Herlihy wrote:

> > > The "standardized" behavior - if std::string or
> > > std::vector is any kind of example - is to implement both
> > > a non-const and const operator[]. By implementing only a
> > > non-const operator[], std::map would appear to be the
> > > exception.

> > The case of std::string is similar in that regard, since
> > it's non-const versions have different semantics (they
> > invalidate iterators), and the same goes for their begin/end
> > functions.

> The non-const version of std::string's operator[] is not
> allowed to invalidate the string's iterators [   21.3/6]

Of course it can.  The last bullet of    21.3/5 says so
explicitly.  The rules are a bit complex, since only the first
call of the operator can invalidate returned iterators, pointers
and references---otherwise, expressions like s[0]==s[1] would be
illegal on a non-const string.

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


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





Author: "kanze" <kanze@gabi-soft.fr>
Date: Mon, 21 Aug 2006 05:06:07 CST
Raw View
jose.diego@gmail.com wrote:
> peter koch wrote:

> > Perhaps Jose thought that operator[] could simply return a
> > value_type::first_type in those situations where the result
> > is used as a rvalue. This can not be done since there is no
> > overload on returnvalue.

> a value_type::second_type default object :-)

> of course it can't be done. there is the reason I am asking if
> there is a proposal for fixing that

> > Another interpretation is how operator[] works on constant maps:

> > #include <map>
> > int main()
> > {
> >   const map<int,int> test;
> >   return test[0];
> > }

> > Is this program ill-formed or will it return 0? I havent got
> > the standard in my hands, but my implementation tells me it
> > is ill-formed.  But my gut feeling is that this should be
> > well-formed and legal.  (Well... why shouldn't it?)

> I think it is a major defect in std::map.
> It should return 0, of course - a temporary
> map::value_type::second_type()

Why?

The problem, of course, is that operator[] returns a reference.
What would the reference refer to?  It can't be a temporary.

One possibility would be to overload with an operator[]() const,
which returned a value.

> as an example VS 2005 gives me that:
> 1>...blablabla.cpp(15) : error C2678: binary '[' : no operator found
> which takes a left-hand operand of type 'const
> Parameter::ParametersMap' (or there is no acceptable conversion)

Which is correct.  In std::map, you cannot use operator[] on a
const map.  And I agree that it is rather a pain.  In my own,
pre-standard hash maps, operator[] returned a pointer, which was
null if the element wasn't present.  Alternatively, you could
use an exception.  Or even provide a contains function and make
it a fatal error to use operator[] with a key where contains
returns false.

--
James Kanze                                           GABI Software
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34


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





Author: "peter koch" <peter.koch.larsen@gmail.com>
Date: Mon, 21 Aug 2006 05:04:55 CST
Raw View
Anders Dalvander wrote:
> chulips wrote:
> > So I think that subscript operator was not originally conceived for
> > "travelling around" the map elements, and that would be a semantic
> > problem. However, changing map::operator[]()  behavior would be a good
> > idea, I think....
>
> Changing map::operator[]() behavior would not be a good idea, as there
> are probably many programs that relies on that behavior.

Of course not.

>
> Adding a new function "const value_type& map<key_type,
> value_type>::at(const key_type& key) const" would probably be better,
> let the function throw an exception if key isn't found (as
> std::vector::at does it). Also adding an overloaded version for
> non-const would make it more symmetric, and easier to use in template
> code.
>
There are two ways of doing it:
let operator[] throw an exception which would be the way std::vector
does it.
let operator[] return a value which is what non-const map does.

I strongly prefer the second solution - i wonder what makes you think
an exception would be more appropriate?

/Peter

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





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Mon, 21 Aug 2006 05:05:34 CST
Raw View
Anders Dalvander wrote:
>
> Changing map::operator[]() behavior would not be a good idea, as there
> are probably many programs that relies on that behavior.

Assuming that the new operator[] would insert an element in a non-const
overload and would only attempt to read in a const-overload would not
be a good modification, not because of it breaking existing code (it
won't) but because someone will think they are doing the const-lookup
(after all they don't modify it) but because the map reference happened
to be non-const they end up inserting an element anyway.

Using operator[] for lazy-evaluation situations is useful. Especially
if the type is shared_ptr and you know it will produce you an empty
shared_ptr when not found. You do have to remember to get the
shared_ptr by reference though or reset() will have no effect on your
map.

> Adding a new function "const value_type& map<key_type,
> value_type>::at(const key_type& key) const" would probably be better,
> let the function throw an exception if key isn't found (as
> std::vector::at does it). Also adding an overloaded version for
> non-const would make it more symmetric, and easier to use in template
> code.

I think many would want it non-throwing. An option is to return a const
pointer rather than a reference. Then it can return a NULL pointer on
not-found. It's very easy to write a free-function to call it and throw
an exception when a NULL pointer gets returned. What you don't want to
have to do is write a function with try..catch blocks. But then it's
easy enough to write a function that calls find() as the OP did above.

Of course, you could now add 2 new functions, one that throws and one
that doesn't.

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





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Mon, 21 Aug 2006 09:49:26 CST
Raw View
Earl Purple wrote:
> Greg Herlihy wrote:
> >
> > But it is possible to overload on the const-ness of the operator[]. For
> > example, std::map's operator[] is currently declared:
> >
> >     T& operator[](const key_type& x);
> >
> > But we could overload operator[] (in very much the same way that
> > std::string does) in order to support indexed access to both const and
> > non-const std::maps:
> >
> >     T& operator[](const key_type& x);
> >     T  operator[](const key_type& x) const;
> >
> > Note that this change would have the nice effect of not breaking any
> > existing code. Instead, the second operator[] would enable a program to
> > use indexed access in order to access the values stored in a const map.
> >
> > Now, there is the question of what would happen if the key index is not
> > found in a const map. The problem is how to communicate this failure to
> > the program. Because any value returned could have been one stored in
> > the map. Moreover, the value returned in this situation would not have
> > been added to the map (since it is const), thereby further misleading
> > the program. For these reasons, a const map would have to throw an
> > exception if operator[] is called with a key not present in the map.
>
> I don't like this for 2 reasons:
>
> - It is too easy to think you are invoking the const method - after all
> you think are you only reading from the map and not modifying anything
> - yet in reality your reference is non-const so you accidentally insert
> an entry to the map you didn't intend to. I'm sure this bug would occur
> too many times.

How could inserting a value for a missing key be unintentional in this
situation? The programmer must be expecting the key to be present in
the std::map, so how could finding the key in the std::map as expected
be an error? std::map's operator[] today returns exactly what the
programmer asks for - and it can do no more than that. Of course it's
possible to ask for things that one does not actually want. But the
Standard Library is not in a position to intuit the programmer's actual
intentions.

In one sense, accessing a std::map exclusively with operator[] makes it
seem as if the map were fully-populated; every key succeeds in
returning (at least a default) value. So whether or not those default
values are actually stored in the map - or whether they might exist as
"virtual" entries (as they would in a const std::map) - is likely to
make little difference to any program using a std::map in this way.

Lastly, it is the case today that any C++ programmer under the
impression that std::map has a const operator[] - has no chance of ever
being right. At least if std::map did have a const operator[], then
that same programmer would at least have a chance of being correct -
occasionally.

Greg

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





Author: "jose.diego@gmail.com" <jose.diego@gmail.com>
Date: Mon, 21 Aug 2006 11:51:06 CST
Raw View
"Gene Bushuyev" wrote:
> <jose.diego@gmail.com> wrote in message
> news:1155678420.260516.259860@74g2000cwt.googlegroups.com...
> >I made the following function to access a map elements to simulate the
> > operator[] in a const map
> >
> > template<typename MapType>
> > const MapType::value_type::second_type get(const MapType map, const
> > MapType::value_type::first_type value) {
> > MapType::const_iterator it = map.find(value);
> > if( it == map.end() ) return MapType::value_type::second_type();
> > return *it;
> > }
> >
> > If the std::map<>::operator[] could be used as an rvalue, it could have
> > the above implementation
> >
> > What do you think?
>
>
> Your solution is already problematic because it breaks the standardized
> behavior. It's highly unlikely that the committee will choose to make changes
> that break a lot of code. On the other hand, no clear logic dictates whether a
> new element should or should not be added to the map or the exception should be
> thrown when operator [] is invoked for non-existing element. I personally would
> prefer exception, but in the final analysis it's not important. Using iterators
> is more logical with associative containers and doesn't have any of these
> problems, and that's what people are accustomed to doing - using find(),
> lower/upper_bound(), etc.
> [ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]

Please can you explain us how will my solution break "a lot of code"?
Currently, STL DOES NOT HAVE operator[] for const maps :-)

Diego Martins
HP

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





Author: "jose.diego@gmail.com" <jose.diego@gmail.com>
Date: Mon, 21 Aug 2006 12:02:12 CST
Raw View
Greg Herlihy wrote:
>
> So after further reflection, I can now see how returning a
> default-initialized value for a missing key would be a better choice
> for a std::map const operator[] than would having it throw an
> exception. After all, if the program really cared whether the key
> exists in the map before attempting to retrieve its value with the
> index operator - then the program would not be using the index operator
> in the first place. And if a program does not care whether the key is
> present in a non-const std::map, then there is little reason to expect
> that would it care in the case of a const std::map to any greater
> extent.

yeah! you clearly got my point, Greg

With my custom function, the code that queries the map reduced
significantly. It got more legible, too.

I really do believe that
T map<...>::operator[](...key) const;
will be quite useful

Diego Martins
HP

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





Author: spam@spamguard.com ("Gene Bushuyev")
Date: Mon, 21 Aug 2006 20:42:36 GMT
Raw View
<jose.diego@gmail.com> wrote in message
news:1156178710.783458.167610@h48g2000cwc.googlegroups.com...
>
> "Gene Bushuyev" wrote:
>> <jose.diego@gmail.com> wrote in message
>> news:1155678420.260516.259860@74g2000cwt.googlegroups.com...
>> >I made the following function to access a map elements to simulate the
>> > operator[] in a const map
>> >
>> > template<typename MapType>
>> > const MapType::value_type::second_type get(const MapType map, const
>> > MapType::value_type::first_type value) {
>> > MapType::const_iterator it = map.find(value);
>> > if( it == map.end() ) return MapType::value_type::second_type();
>> > return *it;
>> > }
>> >
>> > If the std::map<>::operator[] could be used as an rvalue, it could have
>> > the above implementation
>> >
>> > What do you think?
>>
>>
>> Your solution is already problematic because it breaks the standardized
>> behavior. It's highly unlikely that the committee will choose to make changes
>> that break a lot of code. On the other hand, no clear logic dictates whether
>> a
>> new element should or should not be added to the map or the exception should
>> be
>> thrown when operator [] is invoked for non-existing element. I personally
>> would
>> prefer exception, but in the final analysis it's not important. Using
>> iterators
>> is more logical with associative containers and doesn't have any of these
>> problems, and that's what people are accustomed to doing - using find(),
>> lower/upper_bound(), etc.
>> [ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]
>
> Please can you explain us how will my solution break "a lot of code"?
> Currently, STL DOES NOT HAVE operator[] for const maps :-)


Are you forgetting about mutable keyword? Your suggestion will break working
code and it will not be obvious for programmers why and where. It's never a good
idea to change the already standardized behavior without very serious reasons.
So far no such reasons were presented.
Also, creating non-intuitive differences between const and non-const versions
would lead to frequent errors. When a non-const rvalue object is used, it's
typical for programmers to assume that the behavior is the same as for const
object. Designs that break this rule are error-prone.
The only viable (though not perfect) solution for const map operator [] is to
throw an exception, when key is not in the map. It can still break a working
code, but no latent change in behavior can happen.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

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





Author: jth02@arcor.de (Jens Theisen)
Date: Wed, 23 Aug 2006 00:04:25 GMT
Raw View
Gene Bushuyev wrote:
>>Please can you explain us how will my solution break "a lot of code"?
>>Currently, STL DOES NOT HAVE operator[] for const maps :-)
>
> Are you forgetting about mutable keyword?

What about it? Can you make an example?

> Also, creating non-intuitive differences between const and non-const versions
> would lead to frequent errors. When a non-const rvalue object is used, it's
> typical for programmers to assume that the behavior is the same as for const
> object. Designs that break this rule are error-prone.

That's a good point; I wouldn't like to see a const subscript for this
reason.

Jens

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





Author: "Anders Dalvander" <google@dalvander.com>
Date: Thu, 17 Aug 2006 17:53:23 CST
Raw View
chulips wrote:
> So I think that subscript operator was not originally conceived for
> "travelling around" the map elements, and that would be a semantic
> problem. However, changing map::operator[]()  behavior would be a good
> idea, I think....

Changing map::operator[]() behavior would not be a good idea, as there
are probably many programs that relies on that behavior.

Adding a new function "const value_type& map<key_type,
value_type>::at(const key_type& key) const" would probably be better,
let the function throw an exception if key isn't found (as
std::vector::at does it). Also adding an overloaded version for
non-const would make it more symmetric, and easier to use in template
code.

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





Author: "jose.diego@gmail.com" <jose.diego@gmail.com>
Date: Thu, 17 Aug 2006 18:39:17 CST
Raw View
peter koch wrote:
> Perhaps Jose thought that operator[] could simply return a
> value_type::first_type in those situations where the result is used as
> a rvalue. This can not be done since there is no overload on
> returnvalue.

a value_type::second_type default object :-)

of course it can't be done. there is the reason I am asking if there is
a proposal for fixing that

> Another interpretation is how operator[] works on constant maps:
>
> #include <map>
> int main()
> {
>   const map<int,int> test;
>   return test[0];
> }
>
> Is this program ill-formed or will it return 0? I havent got the
> standard in my hands, but my implementation tells me it is ill-formed.
> But my gut feeling is that this should be well-formed and legal.
> (Well... why shouldn't it?)

I think it is a major defect in std::map.
It should return 0, of course - a temporary
map::value_type::second_type()

as an example VS 2005 gives me that:
1>...blablabla.cpp(15) : error C2678: binary '[' : no operator found
which takes a left-hand operand of type 'const
Parameter::ParametersMap' (or there is no acceptable conversion)

:-(

Diego Martins
HP

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





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Fri, 18 Aug 2006 11:09:38 CST
Raw View
peter koch wrote:
> SuperKoko wrote:
> > jose.diego@gmail.com wrote:
> > > I made the following function to access a map elements to simulate the
> > > operator[] in a const map
> > >
> >[...]
> >
> > > If the std::map<>::operator[] could be used as an rvalue, it could have
> > > the above implementation
> > >
> > But... std::map<>::operator[] CAN be used as an rvalue (it can even be
> > used as an lvalue).
> >
> > > What do you think?
> >
> > I don't see your point. Could you be more specific.
> >
> Perhaps Jose thought that operator[] could simply return a
> value_type::first_type in those situations where the result is used as
> a rvalue. This can not be done since there is no overload on
> returnvalue.

But it is possible to overload on the const-ness of the operator[]. For
example, std::map's operator[] is currently declared:

    T& operator[](const key_type& x);

But we could overload operator[] (in very much the same way that
std::string does) in order to support indexed access to both const and
non-const std::maps:

    T& operator[](const key_type& x);
    T  operator[](const key_type& x) const;

Note that this change would have the nice effect of not breaking any
existing code. Instead, the second operator[] would enable a program to
use indexed access in order to access the values stored in a const map.


Now, there is the question of what would happen if the key index is not
found in a const map. The problem is how to communicate this failure to
the program. Because any value returned could have been one stored in
the map. Moreover, the value returned in this situation would not have
been added to the map (since it is const), thereby further misleading
the program. For these reasons, a const map would have to throw an
exception if operator[] is called with a key not present in the map.

Greg

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





Author: "jose.diego@gmail.com" <jose.diego@gmail.com>
Date: Fri, 18 Aug 2006 16:41:58 CST
Raw View
Greg Herlihy wrote:
> But it is possible to overload on the const-ness of the operator[]. For
> example, std::map's operator[] is currently declared:
>
>     T& operator[](const key_type& x);
>
> But we could overload operator[] (in very much the same way that
> std::string does) in order to support indexed access to both const and
> non-const std::maps:
>
>     T& operator[](const key_type& x);
>     T  operator[](const key_type& x) const;
>
> Note that this change would have the nice effect of not breaking any
> existing code. Instead, the second operator[] would enable a program to
> use indexed access in order to access the values stored in a const map.
>
>
> Now, there is the question of what would happen if the key index is not
> found in a const map. The problem is how to communicate this failure to
> the program. Because any value returned could have been one stored in
> the map. Moreover, the value returned in this situation would not have
> been added to the map (since it is const), thereby further misleading
> the program. For these reasons, a const map would have to throw an
> exception if operator[] is called with a key not present in the map.
>
> Greg

I don't know if map is supposed to throw exceptions

FYI, here is the code (tested) I am currently using to access values
from a const map:

/** given a key, search for its corresponding value in a const map
* @param map reference to the map that will be queried
* @param key the key
* @return copy of the value found or a default-constructed value object
(NULL pointers, empty strings, etc.)
* @note actually, any paired container supporting the find method can
be used
*/
template<typename MapType>
const typename MapType::value_type::second_type mapAt(const MapType &
map, const typename MapType::value_type::first_type & key)
{
 typename MapType::const_iterator it = map.find(key);
 if( it == map.end() ) return MapType::value_type::second_type();
 return it->second;
}

Instead of throwing exceptions, I can live with default values :-)

But your idea of const overloading is very good. It even may be a good
proposal to the new standard.

Diego Martins

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





Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Fri, 18 Aug 2006 16:41:03 CST
Raw View
jose.diego@gmail.com wrote:
> peter koch wrote:
> > Perhaps Jose thought that operator[] could simply return a
> > value_type::first_type in those situations where the result is used as
> > a rvalue. This can not be done since there is no overload on
> > returnvalue.
>
> a value_type::second_type default object :-)
>
> of course it can't be done. there is the reason I am asking if there is
> a proposal for fixing that
>
> > Another interpretation is how operator[] works on constant maps:
> >
> > #include <map>
> > int main()
> > {
> >   const map<int,int> test;
> >   return test[0];
> > }
> >
> > Is this program ill-formed or will it return 0? I havent got the
> > standard in my hands, but my implementation tells me it is ill-formed.
> > But my gut feeling is that this should be well-formed and legal.
> > (Well... why shouldn't it?)
>
> I think it is a major defect in std::map.
> It should return 0, of course - a temporary
> map::value_type::second_type()
>
I would not want to have an "operator[] const" having a different
semantic than "operator[]"
Actually, "operator[]" does modify the std::map, since it inserts the
key/value pair if it doesn't exist yet.

It could not be possible to say that operator[] doesn't modify the
std::map and just returns a map::value_type::second_type by value,
because it would not be a lvalue designating the value inside the
object, as would be expected (moreover, breaking actual code is not a
good idea).

But giving a different semantic to operator[] const is really a bad
idea.

It would mean that the programmer has to be very careful (especially in
templates) to know whether the qualifier of the map (or reference to
map) include a const qualifier.

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





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Fri, 18 Aug 2006 23:21:22 CST
Raw View
SuperKoko wrote:
> jose.diego@gmail.com wrote:
> > peter koch wrote:
> > > Another interpretation is how operator[] works on constant maps:
> > >
> > > #include <map>
> > > int main()
> > > {
> > >   const map<int,int> test;
> > >   return test[0];
> > > }
> > >
> > > Is this program ill-formed or will it return 0? I havent got the
> > > standard in my hands, but my implementation tells me it is ill-formed.
> > > But my gut feeling is that this should be well-formed and legal.
> > > (Well... why shouldn't it?)
> >
> > I think it is a major defect in std::map.
> > It should return 0, of course - a temporary
> > map::value_type::second_type()
> >
> I would not want to have an "operator[] const" having a different
> semantic than "operator[]"
> Actually, "operator[]" does modify the std::map, since it inserts the
> key/value pair if it doesn't exist yet.
>
> It could not be possible to say that operator[] doesn't modify the
> std::map and just returns a map::value_type::second_type by value,
> because it would not be a lvalue designating the value inside the
> object, as would be expected (moreover, breaking actual code is not a
> good idea).
>
> But giving a different semantic to operator[] const is really a bad
> idea.

Technically, the semantics of an exception-throwing, const operator[]
for std::map would be the same as the non-const version. But viewed in
terms of a design by contract, the criticism is valid: the
post-conditions and pre-conditions of the two operators[] would differ
significantly.

So after further reflection, I can now see how returning a
default-initialized value for a missing key would be a better choice
for a std::map const operator[] than would having it throw an
exception. After all, if the program really cared whether the key
exists in the map before attempting to retrieve its value with the
index operator - then the program would not be using the index operator
in the first place. And if a program does not care whether the key is
present in a non-const std::map, then there is little reason to expect
that would it care in the case of a const std::map to any greater
extent.

Greg

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





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Sat, 19 Aug 2006 00:19:45 CST
Raw View
SuperKoko wrote:
> jose.diego@gmail.com wrote:
> > peter koch wrote:
> > > Another interpretation is how operator[] works on constant maps:
> > >
> > > #include <map>
> > > int main()
> > > {
> > >   const map<int,int> test;
> > >   return test[0];
> > > }
> > >
> > > Is this program ill-formed or will it return 0? I havent got the
> > > standard in my hands, but my implementation tells me it is ill-formed.
> > > But my gut feeling is that this should be well-formed and legal.
> > > (Well... why shouldn't it?)
> >
> > I think it is a major defect in std::map.
> > It should return 0, of course - a temporary
> > map::value_type::second_type()
> >
> I would not want to have an "operator[] const" having a different
> semantic than "operator[]"
> Actually, "operator[]" does modify the std::map, since it inserts the
> key/value pair if it doesn't exist yet.
>
> It could not be possible to say that operator[] doesn't modify the
> std::map and just returns a map::value_type::second_type by value,
> because it would not be a lvalue designating the value inside the
> object, as would be expected (moreover, breaking actual code is not a
> good idea).
>
> But giving a different semantic to operator[] const is really a bad
> idea.

Technically, the semantics of an exception-throwing, const operator[]
for std::map would be the same as the non-const version. But viewed in
terms of a design by contract, the criticism is valid: the
post-conditions and pre-conditions of the two operators[] would differ
significantly.

So after further reflection, I can now see how returning a
default-initialized value for a missing key would be a better choice
for a std::map const operator[] than would having it throw an
exception. After all, if the program really cared whether the key
exists in the map before attempting to retrieve its value with the
index operator - then the program would not be using the index operator
in the first place. And if a program does not care whether the key is
present in a non-const std::map, then there is little reason to expect
that would it care in the case of a const std::map to any greater
extent.

Greg

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





Author: "Earl Purple" <earlpurple@gmail.com>
Date: Sun, 20 Aug 2006 14:16:19 CST
Raw View
Greg Herlihy wrote:
>
> But it is possible to overload on the const-ness of the operator[]. For
> example, std::map's operator[] is currently declared:
>
>     T& operator[](const key_type& x);
>
> But we could overload operator[] (in very much the same way that
> std::string does) in order to support indexed access to both const and
> non-const std::maps:
>
>     T& operator[](const key_type& x);
>     T  operator[](const key_type& x) const;
>
> Note that this change would have the nice effect of not breaking any
> existing code. Instead, the second operator[] would enable a program to
> use indexed access in order to access the values stored in a const map.
>
> Now, there is the question of what would happen if the key index is not
> found in a const map. The problem is how to communicate this failure to
> the program. Because any value returned could have been one stored in
> the map. Moreover, the value returned in this situation would not have
> been added to the map (since it is const), thereby further misleading
> the program. For these reasons, a const map would have to throw an
> exception if operator[] is called with a key not present in the map.

I don't like this for 2 reasons:

- It is too easy to think you are invoking the const method - after all
you think are you only reading from the map and not modifying anything
- yet in reality your reference is non-const so you accidentally insert
an entry to the map you didn't intend to. I'm sure this bug would occur
too many times.

- I don't think it's a good idea to get an exception where the entry is
not found. Remember that the purpose of exceptions it to detect
environmental errors, i.e. errors that were not expected to occur but
did so because of bad user-input, network failure, etc. And the purpose
should be to report the error back to the user / log-file or wherever.
Now in this instance, how are we going to detect which key was not
found? Will the exception include this in the text? No - it can't
because there is no reason why the key should be printable. Of course,
a lot of the time it will be, but there is no particular reason to
enforce this and ergo it cannot be logged in the exception message. So
this would lead to any programmer who wants to report such an error to
wrap the exception in a try..catch in such a manner to then do
self-detection, and once we're here, we may as well write a
hand-written function that uses find(). I do that anyway when I want
such functionality.

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





Author: spam@spamguard.com ("Gene Bushuyev")
Date: Mon, 21 Aug 2006 10:00:42 GMT
Raw View
<jose.diego@gmail.com> wrote in message
news:1155678420.260516.259860@74g2000cwt.googlegroups.com...
>I made the following function to access a map elements to simulate the
> operator[] in a const map
>
> template<typename MapType>
> const MapType::value_type::second_type get(const MapType map, const
> MapType::value_type::first_type value) {
> MapType::const_iterator it = map.find(value);
> if( it == map.end() ) return MapType::value_type::second_type();
> return *it;
> }
>
> If the std::map<>::operator[] could be used as an rvalue, it could have
> the above implementation
>
> What do you think?


Your solution is already problematic because it breaks the standardized
behavior. It's highly unlikely that the committee will choose to make changes
that break a lot of code. On the other hand, no clear logic dictates whether a
new element should or should not be added to the map or the exception should be
thrown when operator [] is invoked for non-existing element. I personally would
prefer exception, but in the final analysis it's not important. Using iterators
is more logical with associative containers and doesn't have any of these
problems, and that's what people are accustomed to doing - using find(),
lower/upper_bound(), etc.

--
Gene Bushuyev (www.gbresearch.com)
----------------------------------------------------------------
To see what is in front of one's nose needs a constant struggle ~ George Orwell

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





Author: "jose.diego@gmail.com" <jose.diego@gmail.com>
Date: Tue, 15 Aug 2006 18:08:43 CST
Raw View
I made the following function to access a map elements to simulate the
operator[] in a const map

template<typename MapType>
const MapType::value_type::second_type get(const MapType map, const
MapType::value_type::first_type value) {
 MapType::const_iterator it = map.find(value);
 if( it == map.end() ) return MapType::value_type::second_type();
 return *it;
}

If the std::map<>::operator[] could be used as an rvalue, it could have
the above implementation

What do you think?
Diego Martins
HP

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





Author: "SuperKoko" <tabkannaz@yahoo.fr>
Date: Wed, 16 Aug 2006 10:34:53 CST
Raw View
jose.diego@gmail.com wrote:
> I made the following function to access a map elements to simulate the
> operator[] in a const map
>
> template<typename MapType>
> const MapType::value_type::second_type get(const MapType map, const
> MapType::value_type::first_type value) {
>  MapType::const_iterator it = map.find(value);
>  if( it == map.end() ) return MapType::value_type::second_type();
>  return *it;
> }
>
Your code seems incorrect : the typename keyword is mandatory for
accessing MapType::value_type::second_type and
MapType::value_type::first_type (dependent names), and you pass map by
value (very inefficient).


> If the std::map<>::operator[] could be used as an rvalue, it could have
> the above implementation
>
But... std::map<>::operator[] CAN be used as an rvalue (it can even be
used as an lvalue).

> What do you think?

I don't see your point. Could you be more specific.

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





Author: "peter koch" <peter.koch.larsen@gmail.com>
Date: Thu, 17 Aug 2006 07:42:35 CST
Raw View
SuperKoko wrote:
> jose.diego@gmail.com wrote:
> > I made the following function to access a map elements to simulate the
> > operator[] in a const map
> >
> > template<typename MapType>
> > const MapType::value_type::second_type get(const MapType map, const
> > MapType::value_type::first_type value) {
> >  MapType::const_iterator it = map.find(value);
> >  if( it == map.end() ) return MapType::value_type::second_type();
> >  return *it;
> > }
> >
> Your code seems incorrect : the typename keyword is mandatory for
> accessing MapType::value_type::second_type and
> MapType::value_type::first_type (dependent names), and you pass map by
> value (very inefficient).
>
>
> > If the std::map<>::operator[] could be used as an rvalue, it could have
> > the above implementation
> >
> But... std::map<>::operator[] CAN be used as an rvalue (it can even be
> used as an lvalue).
>
> > What do you think?
>
> I don't see your point. Could you be more specific.
>
Perhaps Jose thought that operator[] could simply return a
value_type::first_type in those situations where the result is used as
a rvalue. This can not be done since there is no overload on
returnvalue.
Another interpretation is how operator[] works on constant maps:

#include <map>
int main()
{
  const map<int,int> test;
  return test[0];
}

Is this program ill-formed or will it return 0? I havent got the
standard in my hands, but my implementation tells me it is ill-formed.
But my gut feeling is that this should be well-formed and legal.
(Well... why shouldn't it?)

/Peter

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





Author: "chulips" <chulips@gmail.com>
Date: Thu, 17 Aug 2006 10:13:30 CST
Raw View
Hi Folks,

I agree with Peter, but let consider some comments that I've found
reading some books...

Stroustrup says:

"Subscripting a m a p adds a default element when the key is not found.
Therefore, there is no version of o p e r a t o r []() for c o n s t m
a p s. Furthermore, subscripting can be used only if the m a p p e d _
t y p e (value type) has a default value. If the programmer simply
wants to see if a key is present, the f i n d () operation (   17.4.1.6)
can be used to locate a k e y without modifying the m a p ." (The C++
Programming Language, p.482)

Josuttis says:

"Associative containers don't typically provide abilities for direct
element access. Instead, you must use iterators. For maps, however,
there is an exception to this rule."
..
"The advantage is that you can insert new elements into a map with a
more convenient
interface"
"The disadvantage is that you might insert new elements by accident or
mistake."
(The C++ Standard Library A Tutorial and Reference, p.205)

And also Meyers has comments about that:
"The operator[] function for maps is a novel creature, unrelated to the
operator[] functions for vectors, deques, and strings and equally
unrelated to the built-in operator[] that works with arrays. Instead,
map::operator[] is designed to facilitate "add or update"
functionality."

"It would be nice if the STL provided a function that offered the best
of both worlds, i.e., efficient add-or-update functionality in a
syntatically attractive package."
(Effective STL, p.107)

So I think that subscript operator was not originally conceived for
"travelling around" the map elements, and that would be a semantic
problem. However, changing map::operator[]()  behavior would be a good
idea, I think....

peter koch escreveu:

> SuperKoko wrote:
> > jose.diego@gmail.com wrote:
> > > I made the following function to access a map elements to simulate the
> > > operator[] in a const map
> > >
> > > template<typename MapType>
> > > const MapType::value_type::second_type get(const MapType map, const
> > > MapType::value_type::first_type value) {
> > >  MapType::const_iterator it = map.find(value);
> > >  if( it == map.end() ) return MapType::value_type::second_type();
> > >  return *it;
> > > }
> > >
> > Your code seems incorrect : the typename keyword is mandatory for
> > accessing MapType::value_type::second_type and
> > MapType::value_type::first_type (dependent names), and you pass map by
> > value (very inefficient).
> >
> >
> > > If the std::map<>::operator[] could be used as an rvalue, it could have
> > > the above implementation
> > >
> > But... std::map<>::operator[] CAN be used as an rvalue (it can even be
> > used as an lvalue).
> >
> > > What do you think?
> >
> > I don't see your point. Could you be more specific.
> >
> Perhaps Jose thought that operator[] could simply return a
> value_type::first_type in those situations where the result is used as
> a rvalue. This can not be done since there is no overload on
> returnvalue.
> Another interpretation is how operator[] works on constant maps:
>
> #include <map>
> int main()
> {
>   const map<int,int> test;
>   return test[0];
> }
>
> Is this program ill-formed or will it return 0? I havent got the
> standard in my hands, but my implementation tells me it is ill-formed.
> But my gut feeling is that this should be well-formed and legal.
> (Well... why shouldn't it?)
>
> /Peter
>
> ---
> [ comp.std.c++ is moderated.  To submit articles, try just posting with ]
> [ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
> [              --- Please see the FAQ before posting. ---               ]
> [ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]


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