Re: Overhead of subscript operator for STL maps
Stephen Horne wrote:
On Fri, 17 Oct 2008 17:05:27 GMT, Juha Nieminen
<nospam@thanks.invalid> wrote:
Stephen Horne wrote:
I realise that scripting languages do it, but they get to handle the
[] differently depending on whether its on the left side of an
assignment or not. They still complain if you try to read a
non-existent key.
Actually in many languages (such as for example PHP) relational maps
work exactly that way. That is, you add an element to the map by
"indexing" it with the key and assigning the element. This is a very
common idiom eg. in PHP.
In Ruby it's basically the same with a dictionary. You can overload
index-get and index-assignment separatly, that is, [] and []= are two
different functions/methods. With []= you insert a new element or change
it, with [] you get nil, if the element doesn't exist.
Stephen Horne wrote:
C++ allows key:data insertion using "container [key] = data;". That
surprised me. I realise that scripting languages *also* do "container
[key] = data;", but they get to handle the subscripting differently.
Basically, scripting languages don't do a two stage process of insert
a key:default in the [], then overwrite the default with the data in
the assign. They merge the subscripting and assign into a single step.
Yes. In Ruby, the method [] is called if you want to get a value, and
[]= if you assign to it.
In C++ there's only one operator[] and it is called for read and write.
You can fake the semantics by returning a proxy object that has
operator=(const TYPE&) for assignment and operator TYPE() for reading
the value.
Stephen Horne wrote:
Juha Nieminen wrote:
std::map has that exact same idea (although it's not as flexible as
PHP because the type of the key and the value are fixed). As exemplified
by Erik, this can be quite handy in some cases, for example because you
can write things like:
words[word]++;
One single command adds a new 'word' to the map and increments its value.
You won't get the result you expect, or at least if you do it's only a
fluke.
He will.
Try the following...
#include <map>
#include <iostream>
void Garbage ()
{
char garbage [1024];
for (int i = 0; i < 1024; ++i) garbage [i] = 0x55;
}
That's a completly different case. 'garbage' here is not initialized.
But std::map guarantees that new objects are default-initialized.
Is the same as with std::vector:
std::vector<int> v;
v.resize(10);
The elements don't contain garbage, they are all 0 (zero).
What result do you expect from Test? If you say zero, you're wrong.
The default constructor for int is trivial - it does nothing. The
variable a is never initialised, so it's value is junk. Because of the
specific junk that happens to be on the stack at the time (due to the
prior Garbage call) the most likely output is 2009147472.
In a completely trivial test program you will fluke it - on typical
desktop systems - as the memory is normally wiped to all zero as your
program is loaded. As soon as the program does anything significant,
though...
Getting back to your example, if the key "word" is new, so you insert
a new item, you are incrementing a garbage value - whatever happened
to be in some arbitrary chunk of memory prior to executing that line.
Even that behaviour is only in practice - the standard will say that
the behaviour is undefined.
In general it is true that primitives aren't initialized, but the
standard containers guarantee that they are.
You should read a good book to update your C++.
--
Thomas