【CPP】迭代器失效问题 static和inline

文章目录

  • 迭代器失效
      • **常见的迭代器失效场景**
        • 1. **`std::vector`**
        • 2. **`std::deque`**
        • 3. **`std::list`**
        • 4. **`std::map` / `std::set`**
        • 5. **`std::unordered_map` / `std::unordered_set`**
      • **总结:迭代器失效场景**
      • **如何避免迭代器失效?**
  • static 和 inline
      • 1. `static`
      • 2. `inline`
      • `static` vs `inline`
      • 总结

迭代器失效

在C++中,迭代器失效指的是在容器进行某些操作后,原先获取的迭代器不再指向有效的元素或位置。迭代器失效可能会导致未定义行为(如访问无效内存、程序崩溃等)。不同的容器在特定操作下会有不同的迭代器失效行为。


常见的迭代器失效场景

1. std::vector
  • 失效场景

    1. 插入元素
      • 如果插入导致vector重新分配内存(即容量不足),所有迭代器都会失效。
      • 如果没有重新分配内存,插入点之后的迭代器会失效。
    2. 删除元素
      • 删除点及其之后的迭代器会失效。
    3. resizereserve
      • 如果resizereserve导致内存重新分配,所有迭代器都会失效。
    4. clear
      • 清空容器后,所有迭代器都会失效。
  • 示例

    std::vector<int> vec = {1, 2, 3, 4};
    auto it = vec.begin() + 2;  // 指向3
    vec.push_back(5);           // 可能导致内存重新分配,it失效
    std::cout << *it;           // 未定义行为
    

2. std::deque
  • 失效场景

    1. 插入元素
      • 在两端(push_frontpush_back)插入元素不会使任何迭代器失效。
      • 在中间插入元素会使所有迭代器失效。
    2. 删除元素
      • 在两端(pop_frontpop_back)删除元素不会使任何迭代器失效。
      • 在中间删除元素会使所有迭代器失效。
    3. clear
      • 清空容器后,所有迭代器都会失效。
  • 示例

    std::deque<int> dq = {1, 2, 3, 4};
    auto it = dq.begin() + 2;  // 指向3
    dq.push_back(5);           // it仍然有效
    dq.insert(dq.begin() + 1, 0);  // 所有迭代器失效
    std::cout << *it;          // 未定义行为
    

3. std::list
  • 失效场景

    1. 插入元素
      • 插入元素不会使任何迭代器失效。
    2. 删除元素
      • 只有被删除元素的迭代器会失效,其他迭代器仍然有效。
    3. clear
      • 清空容器后,所有迭代器都会失效。
  • 示例

    std::list<int> lst = {1, 2, 3, 4};
    auto it = ++lst.begin();  // 指向2
    lst.erase(it);            // it失效,但其他迭代器仍然有效
    std::cout << *it;         // 未定义行为
    

4. std::map / std::set
  • 失效场景

    1. 插入元素
      • 插入元素不会使任何迭代器失效。
    2. 删除元素
      • 只有被删除元素的迭代器会失效,其他迭代器仍然有效。
    3. clear
      • 清空容器后,所有迭代器都会失效。
  • 示例

    std::map<int, int> mp = {{1, 10}, {2, 20}, {3, 30}};
    auto it = mp.find(2);  // 指向{2, 20}
    mp.erase(it);          // it失效,但其他迭代器仍然有效
    std::cout << it->second;  // 未定义行为
    

5. std::unordered_map / std::unordered_set
  • 失效场景

    1. 插入元素
      • 如果插入导致重新哈希(rehash),所有迭代器都会失效。
      • 否则,插入不会使迭代器失效。
    2. 删除元素
      • 只有被删除元素的迭代器会失效,其他迭代器仍然有效。
    3. clear
      • 清空容器后,所有迭代器都会失效。
    4. rehash
      • 重新哈希后,所有迭代器都会失效。
  • 示例

    std::unordered_map<int, int> ump = {{1, 10}, {2, 20}, {3, 30}};
    auto it = ump.find(2);  // 指向{2, 20}
    ump.rehash(100);        // 所有迭代器失效
    std::cout << it->second;  // 未定义行为
    

总结:迭代器失效场景

容器类型插入元素删除元素其他操作
std::vector可能全部失效(重新分配内存时)删除点及其后失效resizereserve可能导致失效
std::deque中间插入使全部失效,两端插入不失效中间删除使全部失效,两端删除不失效clear使全部失效
std::list不失效只有被删除元素失效clear使全部失效
std::map / std::set不失效只有被删除元素失效clear使全部失效
std::unordered_map / std::unordered_set可能全部失效(重新哈希时)只有被删除元素失效rehashclear使全部失效

如何避免迭代器失效?

  1. 谨慎操作:在插入或删除元素后,尽量避免使用之前的迭代器。
  2. 更新迭代器:在插入或删除操作后,重新获取迭代器。
  3. 使用返回值:某些操作(如inserterase)会返回新的有效迭代器,可以利用这些返回值。
    auto it = vec.erase(it);  // erase返回下一个有效迭代器
    

理解迭代器失效的场景和规则,可以帮助你编写更安全、更健壮的C++代码。

static 和 inline

在C++中,staticinline 是两种常用于避免函数定义在头文件中多次引用导致链接错误(通常是“多重定义”错误)的方式。它们各自有不同的作用和使用场景:

1. static

  • 当函数或变量声明为 static 时,它的作用域被限制在当前的源文件中(即文件内可见)。因此,即使该头文件被多个源文件引用,每个源文件内部会有自己独立的函数副本,避免了多个源文件之间的符号冲突。
  • static 关键字保证了函数在其他源文件中不可见,不会影响到其他源文件中的相同函数名。

使用示例

// 在头文件中定义 static 函数
static void myFunction() {// 函数实现
}
  • 每个包含该头文件的源文件都会有 myFunction 的独立副本。即使它被多个源文件引用,也不会导致链接错误。

2. inline

  • inline 关键字用于告诉编译器尝试将函数的调用替换为函数体的内容,从而消除函数调用的开销。对于头文件中的函数,使用 inline 可以避免多个定义导致的链接错误,因为编译器会为每个引用的源文件提供该函数的定义,而不会在链接时产生多重定义。
  • 尽管 inline 表示希望进行内联,但更重要的是它能解决多文件中函数多次定义的问题。

使用示例

// 在头文件中定义 inline 函数
inline void myFunction() {// 函数实现
}
  • 使用 inline 后,每个源文件中对该函数的引用都会引入该函数的实现,从而避免了多个源文件之间的链接冲突。

static vs inline

  • static 解决的问题是作用域问题:每个源文件都会有自己的副本,不会发生不同源文件间的符号冲突。
  • inline 主要解决的是性能问题(通过内联化)以及链接问题(避免多重定义)。

常见的用法

  • 如果函数的实现非常简单且短小,通常会同时使用 inlinestatic,这样不仅避免了链接错误,也可能提高效率:
// 在头文件中使用 inline 和 static
static inline void myFunction() {// 函数实现
}

这样,每个源文件在引用头文件时都会有 myFunction 的独立副本,并且编译器可能会将其内联,从而避免了链接错误并提高性能。

总结

  • static 保证函数仅在当前源文件内有效,避免了多文件链接冲突。
  • inline 允许在多个文件中定义相同的函数,而不会导致链接错误,并尝试优化函数调用(通过内联化)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/69012.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

visual studio安装

一、下载Visual Studio 访问Visual Studio官方网站。下载 Visual Studio Tools - 免费安装 Windows、Mac、Linux 在主页上找到并点击“下载 Visual Studio”按钮。 选择适合需求的版本&#xff0c;例如“Visual Studio Community”&#xff08;免费版本&#xff09;&#x…

conda配置channel

你收到 CondaKeyError: channels: value https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main not present in config 错误是因为该镜像源&#xff08;https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main&#xff09;可能没有被正确添加到 Conda 的配置文件中&…

Windows编译FreeRDP步骤

1. **安装必要工具** powershell # 安装 Visual Studio 2022 (勾选"C桌面开发"组件) # 安装 CMake: https://cmake.org/download/ # 安装 Git: https://git-scm.com/ 2. **安装依赖项** powershell # 使用vcpkg包管理 git clone https://github.com/Microsoft/vcpk…

Fortunately 和 luckily区别

Fortunately 和 luckily 的确是同义词&#xff0c;都表示“幸运地”&#xff0c;用于描述某件事发生得很幸运&#xff0c;带有积极、正面的含义。然而&#xff0c;尽管它们的意思相近&#xff0c;fortunately 和 luckily 在使用上有一些细微的差别。 1. 含义相似 Fortunately…

【C语言深入探索】:指针高级应用与极致技巧(二)

目录 一、指针与数组 1.1. 数组指针 1.2. 指向多维数组的指针 1.2.1. 指向多维数组元素的指针 1.2.2. 指向多维数组行的指针 1.3. 动态分配多维数组 1.4. 小结 二、指针与字符串 2.1. 字符串表示 2.2. 字符串处理函数 2.3. 代码示例 2.4. 注意事项 三、指针与文件…

基于开源AI智能名片2 + 1链动模式S2B2C商城小程序源码在抖音招商加盟中的应用与创新

摘要&#xff1a;本文深入探讨了在短视频蓬勃发展的时代背景下&#xff0c;招商加盟领域借助抖音平台所具备的独特优势。同时&#xff0c;全面剖析开源AI智能名片2 1链动模式S2B2C商城小程序源码这一创新工具&#xff0c;详细阐述其如何与抖音招商加盟深度融合&#xff0c;助力…

pthread_cond_broadcast的概念和使用案例

pthread_cond_broadcast 是 POSIX 线程&#xff08;Pthreads&#xff09;库中用于条件变量&#xff08;Condition Variable&#xff09;操作的函数&#xff0c;定义在 <pthread.h> 头文件中。它的核心作用是唤醒所有等待在某个条件变量上的线程&#xff0c;通常用于多线程…

爬虫学习笔记之Robots协议相关整理

定义 Robots协议也称作爬虫协议、机器人协议&#xff0c;全名为网络爬虫排除标准&#xff0c;用来告诉爬虫和搜索引擎哪些页面可以爬取、哪些不可以。它通常是一个叫做robots.txt的文本文件&#xff0c;一般放在网站的根目录下。 robots.txt文件的样例 对有所爬虫均生效&#…

Unity游戏(Assault空对地打击)开发(4) 碰撞体和刚体的添加

前言 飞机和世界的大小关系不太对&#xff0c;我稍微缩小了一下飞机。 详细步骤 选中所有地形对象&#xff0c;如果没有圈起的部分&#xff0c;点击Add Component搜索添加。 接着选中Player对象&#xff0c;添加这两个组件&#xff0c;最好&#xff08;仅对于本项目开发&#x…

【Linux】从硬件到软件了解进程

个人主页~ 从硬件到软件了解进程 一、冯诺依曼体系结构二、操作系统三、操作系统进程管理1、概念2、PCB和task_struct3、查看进程4、通过系统调用fork创建进程&#xff08;1&#xff09;简述&#xff08;2&#xff09;系统调用生成子进程的过程〇提出问题①fork函数②父子进程关…

C语言教学第三课:运算符与表达式

一、课程导入 同学们&#xff0c;上节课我们学习了变量和数据类型&#xff0c;这些是C语言的基础。今天&#xff0c;我们将继续深入学习C语言中的运算符与表达式。运算符是C语言中用于执行各种操作的符号&#xff0c;而表达式则是由变量、常量和运算符组成的有意义的组合。通过…

Maven全解析:从基础到精通的实战指南

概念&#xff1a; Maven 是跨平台的项目管理工具。主要服务基于 Java 平台的构建&#xff0c;依赖管理和项目信息管理项目构建&#xff1a;高度自动化&#xff0c;跨平台&#xff0c;可重用的组件&#xff0c;标准化的流程 依赖管理&#xff1a; 对第三方依赖包的管理&#xf…

MATLAB实现单层竞争神经网络数据分类

一.单层竞争神经网络介绍 单层竞争神经网络&#xff08;Single-Layer Competitive Neural Network&#xff09;是一种基于竞争学习的神经网络模型&#xff0c;主要用于数据分类和模式识别。其核心思想是通过神经元之间的竞争机制&#xff0c;使得网络能够自动学习输入数据的特…

Weevely代码分析

亲测php5和php8都无效&#xff0c;只有php7有效 ailx10 1949 次咨询 4.9 网络安全优秀回答者 互联网行业 安全攻防员 去咨询 上一次做weevely实验可以追溯到2020年&#xff0c;当时还是weevely3.7&#xff0c;现在的是weevely4 生成php网页木马依然差不多…… php菜刀we…

【AI大模型】DeepSeek API大模型接口实现

目录 一、DeepSeek发展历程 2023 年&#xff1a;创立与核心技术突破 2024 年&#xff1a;开源生态与行业落地 2025 年&#xff1a;多模态与全球化布局 性能对齐 OpenAI-o1 正式版​ 二、API接口调用 1.DeepSeek-V3模型调用 2.DeepSeek-R1模型调用 三、本地化部署接口调…

具身智能-强化学习-强化学习基础-马尔可夫

文章目录 参考强化学习基础强化学习特点reward函数两种强化学习两种策略&#xff1a;探索&#xff08;Exploration&#xff09; vs. 利用&#xff08;Exploitation&#xff09;gym库的使用 马尔可夫马尔可夫过程马尔可夫奖励过程&#xff08;Markov Reward Process, MRP&#x…

半导体器件与物理篇5 mosfet及相关器件

认识mos二极管 MOS二极管是研究半导体表面特性最有用的器件之一。MOS二极管可作为存储电容器&#xff0c;并且是电荷耦合器件(CCD)的基本结构单元。 MOS二极管结构的重要参数包括&#xff1a;氧化层厚度d&#xff1b;施加于金属平板上的电压V&#xff08;正偏压时V为正&#x…

pandas习题 071:字典元素列表构造 DataFrame

(编码题)以下有一个列表嵌套字典 data,列表中的每个字典 fields 中的列表为每行数据的值,另有一个 col 为列名,利用这两个数据构造一个 DataFrame。 data = [{fields: [2024-10-07T21:22:01, USER-A, 21, 0,

037 DFS回溯

1.回溯模板求排列 2.回溯模板求子集 # 当前位于点x&#xff0c;步长为length def dfs(x,length):passvis[x]length #接下来走下一个点 #判断下一个点是否走过if vis[a[x]]!0:#此时存在环global ansansmax(ans,length-vis[a[x]]1)else:dfs(a[x],length1)nint(input()) a[0]list(…

#systemverilog# Verilog与SystemVerilog发展历程及关系

1. Verilog的发展历史 1984年:Gateway Design Automation公司开发了Verilog,最初作为专有语言,用于逻辑仿真和数字电路设计。 1990年:Cadence收购Gateway,Verilog逐步开放,成为行业标准。 1995年(IEEE 1364-1995):首个IEEE标准,即Verilog-1995,定义基础语法和仿真语…