对C++中map的三种插入方式的比较及同key值时value覆盖问题

一、map 简介

Map是STL的一个容器,它提供一对一的hash。元素是以键的升序排列的,因为 map 中默认使用 less 函数对象对它们进行排序。
一个map变量中的值以pair的形式存在,可以有多个pair,每个pair中存储两个值。

  1. 第一个为关键字key,每个key只能在map中出现一次,类似数据库中的主键,可以为key指定不同的类型;
  2. 第二个为key对应的值value,二者是一对一的关系,不同的key值可以对应相同的value,可以为key指定不同的类型。

二、map的三种插入方法对比

根据调用的插入函数不同,有三种方式插入map元素:

方式函数key值已存在时是否会覆盖原value值
方法一insert()不会覆盖
方法二emplace()不会覆盖
方法四operator[ ]会覆盖
三种方法的区别:
  • operator[] 与 insert() 的区别主要是,在 map 中已有 key 时,insert() 不会修改 map,而 operator[] 会更新 map 中 key 对应的 value。
  • insert() 与 emplace() 的主要区别是,insert() 先在某个位置新建一个 value_type (在 map 中,这是一个pair),然后根据 key 是否重复,来判断是否插入到 map,而 emplace() 是直接在 map 中新建一个 pair ,然后根据 key 是否重复,来判断是否从 map 中销毁。
  • 通常情况下,emplace() 比 insert() 快,因为减少了对象的创建与移动。
  • 使用 operator[] 时,value 类型需要默认的构造函数。m[1] = value1; 这行代码在执行时,会先使用默认值构造 m[1],然后对 key 赋值。

根据insert()参数的类型不同,insert(),emplace()又有三种方式插入map元素:

方式函数
方法一pair
方法二make_pair
方法三value_type

1. insert() 用法举例:

<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">std::map<std:: string,size_t> people;
// 1. 
people.insert(std::pair<const std::string, size_t> {"Bill", 48}); 
people.insert(std::pair<const std::string, size_t>("Billx", 48));
people.insert({"Bill", 48});
// 2.
people.insert(std::make_pair("Bill", 48));  // make_pair<>() 函数模板的类型参数是从参数类型推断出来的;
people.insert(std::make_pair<std:: string, size_t> (std:: string {"Bill"},48)); // 不依靠隐式转换,z指定类型的 pair 对象
// 3. 
people.insert(map< std::string, size_t>::value_type ("Bill", 48));
</code></span></span>

2. emplace() 用法举例:

<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">    std::map<std::string, size_t> people;
    // 1. 
    people.emplace("c", 48);  // uses pair's template constructor
    // 2. 
    people.emplace(std::make_pair(std::string("a"), 48));  // uses pair's move constructor
    people.emplace(std::make_pair("b", 48));  //uses pair's converting move constructor
    // 3. 
    people.emplace(std::piecewise_construct, std::forward_as_tuple("d"), std::forward_as_tuple(10));  // uses pair's piecewise constructor
</code></span></span>

3. operator[ ]用法举例:

<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">people["Bill"]= 48;
</code></span></span>

三、代码测试

<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">#include <iostream>
#include <map>
#include <string>

using namespace std;

int main()
{
    map<int, string> map_;
    /*insert返回值为pair   原型:typedef pair<iterator, bool> _Pairib
    pair->first=iterator,pair->second=bool;如果插入成功bool=true,失败则flase*/

    /*1、pair插入*/
    pair<map<int, string>::iterator, bool> insert_ok = map_.insert(pair<int, string>(11, "pair"));
    // 判断插入是否成功
    if (insert_ok.second == true) {
        cout << "新值插入成功!" << endl;
    } else {
        cout << "新值插入失败!" << endl;
    }

    /*若key值相同,insert方式插入是否成功*/
    pair<map<int, string>::iterator, bool> insert_false = map_.insert(pair<int, string>(11, "pair_repeat"));
    // 判断插入是否成功
    if (insert_false.second == true) {
        cout << "重复值插入成功!" << endl;
    } else {
        cout << "重复值插入失败!" << endl;
    }

    /*2、make_pair插入*/
    map_.insert(make_pair(22, "make_pair"));
    map_.insert(make_pair(22, "make_pair_repeat"));

    /*3.value_type插入*/
    map_.insert(map<int, string>::value_type(33, "value_type"));
    map_.insert(map<int, string>::value_type(33, "value_type_repeat"));

    /*4.[]插入*/
    map_[44] = "[]";
    map_[44] = "[]_repeat";

    /*输出测试结果*/
    for (map<int, string>::iterator it = map_.begin(); it != map_.end(); it++) {
        cout << it->first << ",\t" << it->second << endl;
    }
    cout << "……………………………………" << endl;

    /*删除map*/
    cout << "正在删除……" << endl;
    while (!map_.empty()) {
        map<int, string>::iterator it = map_.begin();
        cout << it->first << ",\t" << it->second << endl;
        map_.erase(it);
    }
    return 0;
}
</code></span></span>

测试结果如下图:
在这里插入图片描述

四、如何修改指定key对应的value

1. 使用insert()

成员函数 insert() 会返回一个 pair<iterator,bool> 对象。对象的成员 first 是一个迭代器,它要么指向插入元素,要么指向阻止插入的元素。这个对象的成员变量 second (布尔型)是返回对象,如果插入成功,返回值为 true,否则为 false。

如果 map 中已经保存了一个和这个键相同的对象,则插入失败返回指向阻止插入的元素。

当元素已经存在时,如果想将键值“Bill”对应的年龄值改为 48,可以像下面这样使用 insert() 返回的 pair 对象来做到这一点:

<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">ret_pr = people.insert(std::make_pair("Bill", 38));
if(!ret_pr.second)   // 元素("Bill", xxx)已经存在
    ret_pr.first—>second = 48;  //改value值
</code></span></span>

如果不确定元素是否存在,而且仍然想使用插入符,可以使用map 中的 count() 函数,它会返回 map 中指定键对应元素的数目,这个数目可能是 0 或 1。

<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">if (!people.count("Ian"))   // 元素如果不存在,则插入
    people.insert (ret_pr.first, std::make_pair ("Ian", 38));
</code></span></span>

2. 使用operator[]

operator[] 不论元素存在与否,都会将指定值插入到map,如果相同key的元素已经存在,则将value值替换。

<span style="color:#333333"><span style="background-color:#f9f5e9"><code class="language-cpp">std::map<std::string, size_t> people;
people["Bill"]= 48;
people["Bill"]= 50;  // 将{"Bill",48}替换为{"Bill",50}</code></span></span>

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值