【问题标题】:Is it correct to remove elements with std::list::remove using an alias to an element in the container?使用容器中元素的别名使用 std::list::remove 删除元素是否正确?
【发布时间】:2020-01-21 18:58:10
【问题描述】:

当我编译这个程序时:

#include <list>

int main() {
    std::list<int> l = {1, 2};
    l.remove(l.front());
}

通过使用 ASAN 和调试的 clang:

clang++-8 -fno-omit-frame-pointer -g -fsanitize=address -D_GLIBCXX_DEBUG -std=c++11 list-remove.cpp

我收到heap-use-after-free

==31868==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000000020 at pc 0x0000004fa1ae bp 0x7fff52cc5630 sp 0x7fff52cc5628
READ of size 4 at 0x603000000020 thread T0
    #0 0x4fa1ad in std::__debug::list<int, std::allocator<int> >::remove(int const&) /usr/bin/../lib/gcc/x86_64-linux-gnu/7.4.0/../../../../include/c++/7.4.0/debug/list:649:18
    #1 0x4f990f in main /tmp/list-remove.cpp:5:7
    #2 0x7ff27d974b96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310
    #3 0x41b879 in _start (/tmp/list-remove+0x41b879)

似乎当remove 发现x 匹配第一个元素时,它会从列表中删除该元素并将其删除。当它去检查第二个元素时,它会使用已经被删除的x来比较这个元素。

这是根据 C++ 标准的正确实现吗?似乎最好先将元素移动到末尾然后删除它们。这将避免heap-use-after-free 错误,但也许不需要这样的实现。

cppreference 没有提到 value 不能是容器中元素的别名。

这是我正在使用的 c++ 版本:

$ /usr/bin/c++ --version
c++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

【问题讨论】:

  • @FrançoisAndrieux 你是用-D_GLIBCXX_DEBUG构建的吗?
  • 嗯。我们不需要std::remove 在这种情况下工作。我不知道为什么我们需要list::remove,但是缺少措辞。
  • 按原样查看标准,这是一个错误。也就是说,我假设通常的自引用规则应该像 std::remove 一样适用,而是标准存在缺陷并且代码是正确的。
  • 在线草案也没有提到std::list的限制:eel.is/c++draft/list#ops-15std::remove()也没有提到:eel.is/c++draft/alg.remove
  • @NathanOliver 我们只需要移动分配,所以它不可能工作。这是今年四月在图书馆反射器中提出的。反应是……没有同情心。

标签: c++ stl language-lawyer


【解决方案1】:

LWG 526 提出(并回答)了这个问题,其中说:

list::remove(value) 必须工作,因为标准不允许它不能工作。

这已在 libc++ 中修复 back in 2014

【讨论】:

    猜你喜欢
    • 2011-05-14
    • 1970-01-01
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 1970-01-01
    相关资源
    最近更新 更多