10.3.2.map 定义的类型
map 接口的value_type 是 pair 类型,它的值成员可以修改,但键成员不能修改。
map 迭代器进行解引用将产生 pair类型的对象
对迭代器进行解引用时,将获得一个引用,指向容器中一个 value_type 类型的值。对于 map 容器,其 value_type 是 pair 类型。
10.3.4.使用下标访问 map 对象
如下编写程序时:
map <string, int> word_count; // empty map
// insert default initialzed element withkey Anna; then assign 1 to its value
word_count["Anna"] = 1;
使用下标访问 map 与使用下标访问数组或 vector 的行为截然不同:用下标访问不存在的元素将导致在 map 容器中添加一个新元素,它的键即为该下标值。
如同其他下标操作符一样,map 的下标也使用索引(其实就是键)来获取该键所关联的值。如果该键已在容器中,则 map 的下标运算与 vector 的下标运算行为相同:返回该键所关联的值。只有在所查找的键不存在时,map 容器才为该键创建一个新的元素,并将它插入到此map 对象中。此时,所关联的值采用值初始化:类类型的元素用默认构造函数初始化,而内置类型的元素初始化为 0。
10.3.5.map::insert 的使用
map 容器的 insert 成员与顺序容器的类似,但有一点要注意:必须考虑键的作用。键影响了实参的类型:插入单个元素的 insert 版本使用键-值 pair类型的参数。类似地,对于参数为一对迭代器的版本,迭代器必须指向键-值pair 类型的元素。另一个差别则是:map 容器的接受单个值的 insert 版本的返回类型。
以 insert 代替下标运算
使用下标给 map 容器添加新元素时,元素的值部分将采用值初始化。通常,我们会立即为其赋值,其实就是对同一个对象进行初始化并赋值。而插入元素的另一个方法是:直接使用 insert 成员,其语法更紧凑:
// if Anna not already inword_count, inserts new element with value 1
word_count.insert(map<string,int>::value_type("Anna", 1));
这个 insert 函数版本的实参:
map<string,int>::value_type(anna, 1)
使用 insert 成员可避免使用下标操作符所带来的副作用:不必要的初始化。
传递给 insert 的实参相当笨拙。可用两种方法简化:使用 make_pair:
word_count.insert(make_pair("Anna", 1));
或使用 typedef
typedefmap<string,int>::value_type valType;
word_count.insert(valType("Anna", 1));
检测 insert 的返回值
map 对象中一个给定键只对应一个元素。如果试图插入的元素所对应的键已在容器中,则 insert 将不做任何操作。含有一个或一对迭代器形参的 insert函数版本并不说明是否有或有多少个元素插入到容器中。
但是,带有一个键-值 pair 形参的 insert 版本将返回一个值:包含一个迭代器和一个 bool 值的 pair 对象,其中迭代器指向 map 中具有相应键的元素,而 bool 值则表示是否插入了该元素。如果该键已在容器中,则其关联的值保持不变,返回的 bool 值为 true。在这两种情况下,迭代器都将指向具有给定键的元素。
10.3.6.查找并读取 map 中的元素
下标操作符给出了读取一个值的最简单方法:
map<string,int>word_count;
int occurs =word_count["foobar"];
但是,使用下标存在一个很危险的副作用:如果该键不在 map 容器中,那么下标操作会插入一个具有该键的新元素。
这样的行为是否正确取决于程序员的意愿。在这个例子中,如果“foobar”不存在,则在 map 中插入具有该键的新元素,其关联的值为 0。在这种情况下,occurs 获得 0 值。map 容器提供了两个操作:count 和 find,用于检查某个键是否存在而不会插入该键。
使用 count 检查 map 对象中某键是否存在
对于 map 对象,count 成员的返回值只能是 0 或 1。map 容器只允许一个键对应一个实例,所以 count 可有效地表明一个键是否存在。
int occurs = 0;
if(word_count.count("foobar"))
occurs =word_count["foobar"];
当然,在执行 count 后再使用下标操作符,实际上是对元素作了两次查找。如果希望当元素存在时就使用它,则应该用 find 操作。
读取元素而不插入该元素
find 操作返回指向元素的迭代器,如果元素不存在,则返回end 迭代器:
int occurs = 0;
map<string,int>::iterator it =word_count.find("foobar");
if (it != word_count.end())
occurs =it->second;
10.3.7.从 map 对象中删除元素
从 map 容器中删除元素的 erase 操作有三种变化形式(表 10.7)。与顺序容器一样,可向 erase 传递一个或一对迭代器,来删除单个元素或一段范围内的元素。其删除功能类似于顺序容器,但有一点不同:map 容器的 erase 操作返回 void,而顺序容器的 erase 操作则返回一个迭代器,指向被删除元素后面的元素。
10.3.8.map 对象的迭代遍历
与其他容器一样,map 同样提供 begin 和 end 运算,以生成用于遍历整个容器的迭代器。例如,可如下将 map 容器 word_count 的内容输出:
// get iterator positioned on the first element
map<string, int>::const_iterator
map_it = word_count.begin();
// for each element in the map
while (map_it != word_count.end()) {
// print the element key, value pairs
cout << map_it->first << " occurs "
<< map_it->second << " times" << endl;
++map_it; // increment iterator to denote the next element
}