• STL容器的迭代器失效问题

    1 引言

    常见的STL容器都能使用迭代器访问容器内元素,迭代器相同于一个指向容器内元素的指针,可以通过移动迭代器实现遍历容器。
    但是在使用迭代器时需要考虑STL容器的失效问题;迭代器失效主要出现在对容器进行了增删操作之后,迭代器不再指向原本的元素。
    这时如果再通过迭代器访问容器就有可能出现异常。

    2 map容器

    内部数据结构 :红黑树
    插入操作 :插入操作会申请新的节点空间,然后加入都红黑树中,原来的迭代器指向的内存空间都未改变,故不会出现迭代器失效。
    删除操作 :删除操作只会引起被删除节点的迭代器失效。

    3 vector容器

    内部数据结构 :数组(一段连续内存空间)
    插入操作 :由于vector使用的是一段有长度限制的连续空间,插入( push_back / insert )操作在vector中加入新的元素时需要分情况考虑。

    • 当vector中元素总数仍不大于capacity,这时插入位置后的元素都被依次移动到下一个位置,所以插入位置之后的迭代器都会失效。
    • 当vector中元素总数大于capacity,这个时候会重新开辟更大的内存空间,将原来的vector中的内容复制到新的vector中,回收原先vector的内存空间。由于新的vector的地址已完全改变,所以原先的所有迭代器都会失效。

    删除操作 :删除( pop_back / erase )操作在vector中删除元素,删除位置后的元素都被依次复制到前一个位置,所以删除位置之后的迭代器都会失效。
    示例代码:

    4 list容器

    内部数据结构 :双向环状链表
    插入操作 :插入操作会申请新的节点空间,然后加入到链表中,原来的迭代器指向的内存空间都未改变,故不会出现迭代器失效。
    删除操作 :删除操作只会引起被删除节点的迭代器失效。

    5 小结

    在操作STL容器时,对容器增删( erase / insert )之后应该注意接收返回值,这样可以有效避免迭代器失效的产生。
    对容器进行遍历删除操作时,另一种语法技巧是在 erase 接口中对迭代器进行后自增(it++),这种写法也能够保证遍历正常进行。理解这种写法需要参考运算符重载的相关知识,后自增操作会产生一个临时变量用于函数返回。

  • 关于size_t和size_type的比较

    1 引言

    编程中常见的表示两种大小的类型标识符有 size_t 和 size_type ,这两种类型十分相似,非常容易混淆。本文对他们的使用场景进行了比较,并提供了示例代码。

    2 size_t 类型

    当需要描述某个对象的大小(size)时都应该使用 size_t ,其大小被限制为 0 到 SIZE_MAX 之间。
    size_t 的定义在 <cstddef> 中, SIZE_MAX 的定义在 <climits> 中。
    size_t 一般会作为 sizeof 运算符的返回结果,可以理解为在给定的平台中是统一的。

    3 size_type 类型

    在 STL 中定义了 size_type 是与 Allocator::size_tpye 相对应的。而 Allocator 是模板的一个参数。
    size_type 可以理解为在给定容器范围内是统一的。

    4 二者之间的比较

    这两种类型主要是为了提高代码的可移植性。一般情况来说,这两种类型是没有区别的,因为使用标准库默认的 Allocator 所对应的 size_type 就是 size_t 。

    5 示例代码

    注意 size_type 在使用时需要加上容器类型限定。

    std::size_t n1 = sizeof(int);
    
    std::vector<int> v;
    std::vector<int>::size_type n2 = v.size();
    
    std::string s;
    std::string::size_type n3 = s.size();
    
  • 常见的由于语法不当引起的编译警告

    1 引言

    本文主要总结了笔者自己的开发中遇到的不规范的代码写法。这些代码风格可能并不会引起错误,但是会产生隐患或容易引起歧义。
    这些语法缺陷可以通过合理配置编译器的编译选项检查出来,对于编译器的警告配置在前面有文章进行了简单介绍。

  • 在emacs中使用GNU Global的配置指南

    1 引言

    本文主要针对emacs中的global的配置和使用方法做了简要介绍。global是代码标签化索引工具,能够在许多源码中快速定位函数的实现位置。我主要使用global来辅助代码跳转;还有一种用法是用来辅助代码补全,目前正在研究中。

  • GCC编译时的警告(warn)相关参数

    编译阶段警告信息有助于排查代码中错误,合理配置编译警告信息能够提高开发效率。
    通过了解编译警告,也能够了解到哪些代码风格是不好的,有哪些代码的书写格式是容易出现问题的,有助于让自己写出更高质量的代码。

  • Linux 系统目录结构

    Linux系统的目录结构以及各个目录的作用

    /bin

    bin是binary的缩写,这个目录存放使用者最经常使用的命令

    /boot

    这里存放的是启动linux时使用的一些核心文件

    /etc

    这个目录用来存放系统管理所需要的配置文件和子目录

  • Linux下使用gdb的调试技巧

    1 代码编译阶段

    在调试C/C++代码时,在编译阶段使用 gcc/g++ -g 命令编译,将调试信息生成在目标文件中。

    2 开启gdb模式

    • 直接进入gdb模式: gdb
    • 使用gdb模式开启一个新的进程: gdb <appname>
    • 使用指定的程序来调试core文件: gdb <appname> <corename>
  • 终于,博客开通了

    1 前言

    Samson的博客开通了。
    作为码农,一直想要有个博客作为学习与积累的记录。
    在尝试过多种主流博客套路之后,终于选定了使用 emacs + org-mode + nikola + github pages 组合的技术方案。