【c++】8.map和vector容器查找、删除指定元素、emplace、insert

2024-06-16 21:38

本文主要是介绍【c++】8.map和vector容器查找、删除指定元素、emplace、insert,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.查找与删除 vector 和 map 容器中指定元素

vector
查找或删除vector的指定元素"123"

方法1:使用迭代器
不同于map(map有find方法),vector本身没有find这一方法.

std::vector<std::string> vct_name_;
auto iter = vct_name_.begin();
while(iter != vct_name_.end()) {if(*iter=="123"){ 		 // 这命令可以作为查找vetor元素的方法vct_name_.erase(iter);	 // 删除//iter=vct_name_.erase(iter); //也可以这么写}
}

方法2:使用 std::remove_if

std::vector<std::string> vct_name_;
vct_name_.erase(std::remove_if(vct_name_.begin(),vct_name_.end(),[](std::string str) { return str == "123"; }),vct_name_.end());
map
(1) 查找map的关键字:

std::map<std::string,int> map_name_;

auto iter = map_name_.find("key_name");
if (iter != map_name_.end()) {//找到了该关键字,进行的操作
}
(2) 删除map的指定key值

有多种方法:

  • 正确用法1: 直接删除key
    map_name_.erase("key_name");

  • 正确用法2: 使用find()时,可以直接删除迭代器

auto iter = map_name_.find("key_name");
if (iter != map_name_.end()) {map_name_.erase(iter);  //删除
}
  • 正确用法3:iter = name_age_map.erase(iter);
  • 正确用法4: map_name_.erase(iter++);
  • 错误用法: map_name_.erase(iter); iter++;
上面 正确用法4错误用法 两种情况执行序列是不相同的:
  • 前者map_name_.erase(iter++); 在erase执行前进行了加操作,在it被删除(失效)前进行了加操作,是安全的;

  • 后者map_name_.erase(iter); iter++;是在erase执行后才进行加操作,而此时iter已经被删除(当前的迭代器已经失效了),对一个已经失效的迭代器进行加操作,行为是不可预期的,这种写法势必会导致 map操作的失败并引起进程的异常。

原文链接:https://blog.csdn.net/weixin_43778179/article/details/105157228

以下原文链接:https://blog.csdn.net/nisxiya/article/details/47070827

C++ STL中的map是非常常见的。通常我们用如下方式来遍历,并且删除map中的一些entry:

不安全的删除方法:
map<int, int> mp;
mp.insert(make_pair(1,1));
mp.insert(make_pair(2,3)); // insert some elements
for (map<int, int>::iterator iter = mp.begin(); iter != mp.end(); iter++) {if (iter->first == 1) mp.erase(iter); // Unsafe!else iter->second++;
}

上面的删除并不安全,因为mp.erase(iter)之后,iter的结构已经改变了,此时 for循环张的iter++ 可能会出现问题。因此推荐下面的改法:

安全的删除方法:
for (map<int, int>::iterator iter = mp.begin(); iter != mp.end(); ) {if (iter->first == 1) mp.erase(iter++); // SAFE!else iter->second++;
}

这里的删除是安全的,因为iter在删除前已经会先进行缓存一下,再传给erase去删除。因此iter++是在原先的iter 基础上进行的。这种方式也是C++ 文档中推荐的方式。

2.源码示例

map的erase(iter)需注意,和vector不一样

https://blog.csdn.net/zhangyueweia/article/details/50293965

#include <iostream>
#include <map>
#include <string>
#include <vector>// g++ -std=c++11 main.cpp -o mainint main() {// std::vector可以直接删除iter后不影响遍历std::vector<std::string> name_vct = {"Alibaba", "Baidu", "CMD", "DDS","Ella"};std::vector<std::string>::iterator it = name_vct.begin();while (it != name_vct.end()) {std::cout << "*it= " << *it << std::endl;if (*it == "CMD") {name_vct.erase(it);std::cout << "erase后 *it= " << *it << std::endl;} else {++it;}}std::cout << std::endl;std::map<std::string, int> name_age_map = {{"AAA", 21}, {"Bob", 22}, {"Cool", 23}, {"Daisy", 24}};/**  下面这种方式会出错。 std::map 删除iter后继续遍历会造成double free **//*auto it0 = name_age_map.begin();while (it0 != name_age_map.end()) {std::cout << "key= " << it0->first << std::endl;if (it0->first == "Bob") {name_age_map.erase(it0);  //当这条语句执行完后,it0就是一个非法指针,如果再执行++就会出错. std::cout << "erase后  it0->first << std::endl; } else {++it0;}}*//** --方法1* std::map删除iter需要这么使用,使用一个临时变量保存迭代器后,将迭代器自增1**//*while  (it1 != name_age_map.end()) {std::cout << "key= " << it1->first << std::endl;if (it1->first == "Bob") {auto iter_tmp = it1;++it1;name_age_map.erase(iter_tmp);std::cout << "erase后 iter_tmp->first= " << iter_tmp->first << std::endl; std::cout << "erase后 it1->first= " << it1->first << std::endl;} else {++it1;}}*//** --方法2* std::map删除iter需要这么使用,it2 = name_age_map.erase(it2);**//*auto it2 = name_age_map.begin();while (it2 != name_age_map.end()) {std::cout << "key= " << it2->first << std::endl;if (it2->first == "Bob") {it2 = name_age_map.erase(it2);std::cout << "erase后 it2->first= " << it2->first << std::endl;} else {++it;}}
*//** --方法3* std::map删除iter需要这么使用,name_age_map.erase(it3++);**/auto it3 = name_age_map.begin();while (it3 != name_age_map.end()) {std::cout << "key= " << it3->first << std::endl;if (it3->first == "Bob") {name_age_map.erase(it3++);std::cout << "erase后 it->first= " << it3->first << std::endl;} else {++it3;}}
}

3. map 的insert和emplace方法

参考地址: https://www.cnblogs.com/khacker/p/10479801.html
对于两种map容器 std::mapstd::unordered_map:
insert(std::make_pair(key, value))emplace(std::make_pair(key, value))重复插入同一个key的操作,二者都不会替换原先的key对应的value值,只有索引[]操作会改变value。
以下是验证代码示例:

    std::unordered_map<int, int > map;map.insert(std::make_pair(1, 1));map.insert(std::make_pair(2, 2));map.insert(std::make_pair(3, 3));map.insert(std::make_pair(1, 4)); //这一步并不会改变key为1的value值,仍旧是1,不会变为4
	std::unordered_map<int, int > map;map.emplace(1, 1);map.emplace(2, 2);map.emplace(3, 3);map.emplace(1, 4);  //这一步并不会改变key为1的value值,仍旧是1,不会变为4
    map[1] = 1;map[2] = 2;map[3] = 3;map[1] = 4; //这句话会改变key为1的value值,变为4
可以使用以下方式插入key-value键值对 和 更新键值value
  • 如果不存在key,则使用insert()emplace()进行插入键值对;通过前面的知识,我们知道,也可以直接使用[]的当时直接插入键,并进行赋值。
  • 如果存在key,则使用[]进行赋值;
if(map.count(key)){map.insert(std::make_pair(key, value));map.emplace(std::make_pair(key, value));//map[key]=value;  //这种方式也可以
}else{map[key]=value;
}

这篇关于【c++】8.map和vector容器查找、删除指定元素、emplace、insert的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1067619

相关文章

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

Python一次性将指定版本所有包上传PyPI镜像解决方案

《Python一次性将指定版本所有包上传PyPI镜像解决方案》本文主要介绍了一个安全、完整、可离线部署的解决方案,用于一次性准备指定Python版本的所有包,然后导出到内网环境,感兴趣的小伙伴可以跟随... 目录为什么需要这个方案完整解决方案1. 项目目录结构2. 创建智能下载脚本3. 创建包清单生成脚本4

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C#高效实现Word文档内容查找与替换的6种方法

《C#高效实现Word文档内容查找与替换的6种方法》在日常文档处理工作中,尤其是面对大型Word文档时,手动查找、替换文本往往既耗时又容易出错,本文整理了C#查找与替换Word内容的6种方法,大家可以... 目录环境准备方法一:查找文本并替换为新文本方法二:使用正则表达式查找并替换文本方法三:将文本替换为图