C++ vector 访问元素用 at and [] 有什么区别?

前言: 最近同事开发过程遇到了一个奇怪的coredump问题,崩溃位置和提交改动没有任何关系,看了几小时后来才发现原来是vector越界访问了,使用了[]越界访问元素。在此,记录一下at()[]的区别,便于日后可以更快速地定位问题。

1. 源码对比

  • operator[]

/* This operator allows for easy, array-style, data access. - Note that data access with this operator is unchecked and
- out_of_range lookups are not defined. (For checked lookups
- see at().)
- */ reference operator[](size_type __n) _GLIBCXX_NOEXCEPT { __glibcxx_requires_subscript(__n); return *(this->_M_impl._M_start + __n); }

从以上代码以及注释可以看出, []下标运算符不会做越界访问保护,而且不会抛出异常,所以使用[]访问元素时,需要自己做越界检查,否则可能会导致未定义的行为。

  • at()

/* This function provides for safer data access. The parameter - is first checked that it is in the range of the vector. The
- function throws out_of_range if the check fails.
- */ reference at(size_type __n) { _M_range_check(__n); return (*this)[__n]; }

从源码中可以看到,at()函数会做越界访问保护,如果越界会抛出out_of_range异常,然后再通过operator[]运行访问。

2. 代码测试

  • []

以下代码不会抛出异常,但是会导致未定义的行为,程序继续运行,但程序可能在某个时候崩溃,增加了问题定位难度。


std::vector<int> arr; arr[1]; //
  • at()

以下代码会抛出out_of_range异常,在访问元素时立即崩溃。


std::vector<int> arr; arr.at(1);

3. 如何快速定位内存错误?

ASAN(gcc address sanitizer)是一个内存错误检测工具,可以检测内存越界访问,内存泄漏等问题。

例如以下程序:


int func() { std::vector<int> arr; return arr[1]; } std::cout<<func()<<std::endl;

通过以下命令编译程序,然后运行程序:


g++ -g -fsanitize=address -fno-omit-frame-pointer -o vector_test vector_test.cpp ./vector_test

当程序发生内存错误时,会打印出错误信息:


AddressSanitizer:DEADLYSIGNAL ================================================================= ==2026418==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000004 (pc 0x5615f166641e bp 0x7ffde401e7d0 sp 0x7ffde401e720 T0) ==2026418==The signal is caused by a READ memory access. ==2026418==Hint: address points to the zero page. #0 0x5615f166641d in func() /home/qiang/CppTest/vector_test.cpp:7 #1 0x5615f16664af in main /home/qiang/CppTest/vector_test.cpp:12 #2 0x7fa0b1af7082 in __libc_start_main ../csu/libc-start.c:308 #3 0x5615f166626d in _start (/home/qiang/CppTest/vector_test+0x126d) AddressSanitizer can not provide additional info. SUMMARY: AddressSanitizer: SEGV /home/qiang/CppTest/vector_test.cpp:7 in func() ==2026418==ABORTING

4. 结论

  • 当对效率要求较高时,使用[]访问元素,但是需要自己做越界检查。
  • 当对效率要求不高时,使用at()访问元素,会做越界检查,如果越界会抛出out_of_range异常。

5. 启示

当发生奇怪的coredump时,可以尝试使用ASAN等工具检测内存错误,可以快速定位问题。


你好,我是七昂,致力于分享C++、操作系统、软件架构、机器学习、效率提升等系列文章。希望我们能一起探索程序员修炼之道,高效学习、高效工作。如果我的创作内容对您有帮助,请点赞关注。如果有问题,欢迎随时与我交流。感谢你的阅读。

{{uploading-image-322250.png(uploading...)}}

C++ vector 访问元素用 at 和 [] 有什么区别?的更多相关文章

  1. DOM访问元素样式和操作元素样式

    在HTML中定义样式的方式有三种:通过<link/>元素包含外部样式表文件(外部样式表).使用<style/>元素定义嵌入式样式(嵌入式样式表).使用style特性定义针对特定 ...

  2. 【JavaScript】frame跨域访问元素

    什么是跨frame访问元素呢?比如main.html中有如下代码: <frameset cols="50%,*"> <frame src="frame1 ...

  3. PAT 甲级 1053 Path of Equal Weight (30 分)(dfs,vector内元素排序,有一小坑点)

    1053 Path of Equal Weight (30 分)   Given a non-empty tree with root R, and with weight W​i​​ assigne ...

  4. auto_ptr为什么不能做为vector的元素

    昨天看effectve c++的时候,发现了auto_ptr这个东西.由于我待过的公司都是用的老版c++,代码里智能指针什么的完全没有出现过,都是直接操作的原始指针.虽说我很少出错,但是总归还是不太安 ...

  5. 【C++】Vector判断元素是否存在,去重,求交集,求并集

    1 #include <iostream> 2 #include <vector> 3 #include <algorithm> //sort函数.交并补函数 4 ...

  6. 【转】STL中vector、list、deque和map的区别

    1.vector 向量 相当于一个数组 在内存中分配一块连续的内容空间进行存储.支持不指定vector大小的存储.STL内部实现时,首先分配一个非常大的内存空间预备进行存储,即capacity()函数 ...

  7. Java容器类List、ArrayList、Vector及map、HashTable、HashMap的区别与用法

    Java容器类List.ArrayList.Vector及map.HashTable.HashMap的区别与用法 ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数 ...

  8. 元素(Element)和结点(Node)的区别(org.w3c.dom)

    1.元素(Element)和结点(Node)的区别, 元素是一个小范围的定义,必须是含有完整信息的结点才是一个元素,例如 - . 但是一个结点不一定是一个元素,而一个元素一定是一个结点. 什么是nod ...

  9. html元素中id和name的区别

    可以说几乎每个做过Web开发的人都问过,到底元素的ID和Name有什么区别阿?为什么有了ID还要有Name呢?! 而同样我们也可以得到最classical的答案:ID就像是一个人的身份证号码,而Nam ...

  10. jQuery获得元素位置offset()和position()的区别

    jQuery获得元素位置offset()和position()的区别 jQuery 中有两个获取元素位置的方法offset()和position(),这两个方法之间有什么异同 offset(): 获取 ...

随机推荐

  1. Oracle 日期减年数、两日期相减

    -- 日期减年数 SELECT add_months(DEF_DATE,12*USEFUL_LIFE) FROM S_USER --两日期相减 SELECT round(sysdate-PEI.STA ...

  2. linux实现SSH免密登录设置,以及shell脚本实现

    分享/朱季谦 最近在搭建linux集群,做了SSH免密登录的设置,正好把过程记录一下: 一.用搭建好的两台虚拟机做演示,A机器:192.168.200.129,B机器:192.168.200.128 ...

  3. Java-继承Thread的方式和实现Runnable接口多线程

    继承Thread的方式实现多线程 public class TestThread extends Thread{ @Override public void run() { System.out.pr ...

  4. oeasy教您玩转vim - 16 - # 行内贴靠

    行头行尾 回忆上节课内容 跳跃 向前跳跃是 f 向后跳跃是 F 继续 保持方向是 ; 改变方向是 , 可以加上 [count] 来加速 还有什么好玩的吗? 动手 #这次还是用无配置的方式启动 vi - ...

  5. oeasy教您玩转python - 002 - # 你好世界 - 各位同学除夕快乐,除旧布新之时预祝能玩

    ​ 你好世界 回忆上次内容 了解了 Python 安装了 Python 进入了 Python 退出了 Python 可是我们什么也没有做就离开了 IDLE 游乐场! 你好世界 #首先进入Python3 ...

  6. [rCore学习笔记 09]为内核支持函数调用

    在[[08 内核第一条指令|上一节]]我们使用了编写entry.asm函数中编写了内核的第一条指令,但是我们使用的汇编.这里注意我们仍然是嵌入了这段asm代码到我们的rust代码之中,然后进行编译.但 ...

  7. vue中使用xlsx导出excel文件

    俗话说,前人栽树,后人乘凉,感谢强人封装好的xlsx,直接使用就可以了.这是网上找到的,也不知道原作者是不是这位博主,先贴出来吧: https://www.cnblogs.com/boylxx/p/1 ...

  8. 题解:P10733 [NOISG2019 Prelim] Lost Array

    题解:P10733 [NOISG2019 Prelim] Lost Array 思路 对于任意 \(\min(X_{A_{i}},X_{B_{i}})=C_{i}\). 只要让 \(X_{A_{i}} ...

  9. 使用git(ee的一个小总结

    我先把后端项目推进了gitee,后面为了方便又想把前端也放在同一个项目里,结果出问题了: 一开始是因为前端项目内包含了.git的文件(这个玩意还是隐藏文件,就是你在idea里其实是看不到他的),导致只 ...

  10. Ubuntu16.04设置静态IP或动态ip(DHCP)

    Ubuntu16.04设置静态IP或动态ip(DHCP) 设置静态IP 1,vim编辑/etc/network/interfaces 网络配置文件 sudo vim /etc/network/inte ...