如果 `size()` 为 0,如何从 `pop_back()` 得到错误?

How do I get an error from `pop_back()` if `size()` is 0?

我正在向一位同事解释为什么我们要对他们进行消毒剂小测试。他询问了关于多次弹出向量的问题,如果它是一个异常,断言,UB 以及哪个消毒剂捕获它

看来 NONE 抓住了他们。如果你在弹出太多次后调用 back(),地址和内存将会出现,但如果你弹出并执行 size(),由于包装

,你会得到一个很大的无效值

有什么方法可以在弹出次数过多时获得断言或异常或运行时终止?我真的认为没有消毒剂的调试版本会捕捉到这一点(有断言或异常)

我使用 clang sanitizer,但使用 gcc 构建选项也会有帮助

libstdc++ 和 libc++ 都有带断言的“调试模式”,可以使用以下方式启用:

  • -D_GLIBCXX_DEBUG 用于 libstdc++
  • -D_LIBCPP_DEBUG 用于 libc++

-fsanitize=undefined 似乎也能捕捉到它,但错误消息更加神秘。

消毒剂可能需要一些注释才能在库类型上做好工作。 g++ -fsanitize=address -D_GLIBCXX_SANITIZE_VECTOR (documentation), clang++ -stdlib=libc++ -fsanitize=address or clang++ -stdlib=libstdc++ -fsanitize=address -D_GLIBCXX_SANITIZE_VECTOR -D__SANITIZE_ADDRESS__ (the need for this last macro is a bug) 全部检测到问题并打印消息

=================================================================
==12312==ERROR: AddressSanitizer: bad parameters to __sanitizer_annotate_contiguous_container:
      beg     : 0x602000000010
      end     : 0x602000000014
      old_mid : 0x602000000010
      new_mid : 0x60200000000c
    #0 0x7f6a9db3b707 in __sanitizer_annotate_contiguous_container ../../../../src/libsanitizer/asan/asan_poisoning.cpp:362
    #1 0x55b9dcd1fc41 in std::_Vector_base<int, std::allocator<int> >::_Vector_impl::_Asan<std::allocator<int> >::_S_adjust(std::_Vector_base<int, std::allocator<int> >::_Vector_impl&, int*, int*) (/tmp/a.out+0x1c41)
    #2 0x55b9dcd1fb66 in std::_Vector_base<int, std::allocator<int> >::_Vector_impl::_Asan<std::allocator<int> >::_S_shrink(std::_Vector_base<int, std::allocator<int> >::_Vector_impl&, unsigned long) (/tmp/a.out+0x1b66)
    #3 0x55b9dcd1f6c4 in std::vector<int, std::allocator<int> >::pop_back() (/tmp/a.out+0x16c4)
    #4 0x55b9dcd1f36d in main (/tmp/a.out+0x136d)
    #5 0x7f6a9d57fe49 in __libc_start_main ../csu/libc-start.c:314
    #6 0x55b9dcd1f199 in _start (/tmp/a.out+0x1199)

SUMMARY: AddressSanitizer: bad-__sanitizer_annotate_contiguous_container ../../../../src/libsanitizer/asan/asan_poisoning.cpp:362 in __sanitizer_annotate_contiguous_container
==12312==ABORTING

请注意,对于这种情况,不需要像消毒剂那样复杂的东西,正如另一个答案中提到的,图书馆通常有调试模式。例如对于 libstdc++,定义 _GLIBCXX_DEBUG 启用完整调试模式(ABI 与正常模式不兼容)

/usr/include/c++/11/debug/vector:523:
In function:
    void std::__debug::vector<_Tp, _Allocator>::pop_back() [with _Tp = int; 
    _Allocator = std::allocator<int>]

Error: attempt to access an element in an empty container.

Objects involved in the operation:
    sequence "this" @ 0x0x7ffe20bf5f80 {
      type = std::__debug::vector<int, std::allocator<int> >;
    }

在定义 _GLIBCXX_ASSERTIONS 时启用更轻量级的断言并保留 ABI,但提供的错误信息较少

/usr/include/c++/11/bits/stl_vector.h:1227: void std::vector<_Tp, _Alloc>::pop_back() [with _Tp = int; _Alloc = std::allocator<int>]: Assertion '!this->empty()' failed.

并使用 libc++ 打印定义 _LIBCPP_DEBUG

/usr/lib/llvm-11/bin/../include/c++/v1/vector:1703: _LIBCPP_ASSERT '!empty()' failed. vector::pop_back called for empty vector