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

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...)}}

posted on 2024-01-19 00:06  七昂的技术之旅  阅读(341)  评论(0编辑  收藏  举报

导航