Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |
An ordinary array uses an integral value to index into a
sequential set of elements of some type. A map is an associative array, which means you associate one object with another in an array-like
fashion. Instead of selecting an array element with a number as you do with an
ordinary array, you look it up with an object! The example that follows counts
the words in a text file, so the index is the string object representing
the word, and the value being looked up is the object that keeps count of the
strings.
In a single-item container such as a vector or a list,
only one thing is being held. But in a map, you ve got two things: the key (what you look up by, as in mapname[key]) and the value
that results from the lookup with the key. If you simply want to move through
the entire map and list each key-value pair, you use an iterator, which
when dereferenced produces a pair object containing both the key and the
value. You access the members of a pair by selecting first or second.
This same philosophy of packaging two items together is also
used to insert elements into the map, but the pair is created as part of
the instantiated map and is called value_type, containing the key
and the value. So one option for inserting a new element is to create a value_type
object, loading it with the appropriate objects and then calling the insert( )
member function for the map. Instead, the following example uses the
aforementioned special feature of map: if you re trying to find an
object by passing in a key to operator[ ] and that object doesn t
exist, operator[ ] will automatically insert a new key-value pair
for you, using the default constructor for the value object. With that in mind,
consider an implementation of a word-counting program:
//: C07:WordCount.cpp
// Count occurrences of words using a map.
#include <iostream>
#include <fstream>
#include <map>
#include <string>
#include "../require.h"
using namespace std;
int main(int argc, char* argv[]) {
typedef map<string, int> WordMap;
typedef WordMap::iterator WMIter;
const char* fname = "WordCount.cpp";
if(argc > 1) fname = argv[1];
ifstream in(fname);
assure(in, fname);
WordMap wordmap;
string word;
while(in >> word)
wordmap[word]++;
for(WMIter w = wordmap.begin(); w != wordmap.end();
w++)
cout << w->first << ": "
<< w->second << endl;
} ///:~
This example shows the power of zero-initialization. Consider this line of code from the program:
This expression increments the int associated with word.
If there isn t such a word in the map, a key-value pair for the word is
automatically inserted, with the value initialized to zero by a call to the
pseudo-constructor int( ), which returns a 0.
Printing the entire list requires traversing it with an
iterator. (There s no copy( ) shortcut for a map unless you
want to write an operator<< for the pair in the map.) As
previously mentioned, dereferencing this iterator produces a pair
object, with the first member the key and the second member the
value.
If you want to find the count for a particular word, you can
use the array index operator, like this:
cout << "the: " << wordmap["the"] <<
endl;
You can see that one of the great advantages of the map
is the clarity of the syntax; an associative array makes intuitive sense to the
reader. (Note, however, that if the isn t already in the wordmap, a
new entry will be created!)
Thinking in C++ Vol 2 - Practical Programming |
Prev |
Home |
Next |