Vector.erase 中的 SIGSEGV

Posted

技术标签:

【中文标题】Vector.erase 中的 SIGSEGV【英文标题】:SIGSEGV in Vector.erase 【发布时间】:2015-12-31 11:50:55 【问题描述】:

当我擦除向量中的元素时,我遇到了一个奇怪的分段错误错误。这是代码:

int i = 0;
    cout << "SIZE: " << OrderList::sellOrders.size();
    for(vector<Order>::iterator it = OrderList::sellOrders.begin(); it != OrderList::sellOrders.end(); it++, i++)
    
        if(OrderList::sellOrders[i].pThis->usesWamp() == false)
        
            cout << "Erase element " << i << endl;
            OrderList::sellOrders.erase(it);
        
    

输出是这样的:

SIZE: 44
Erase element 0
Erase element 2
Erase element 3
Erase element 4
Erase element 5
Erase element 6
Erase element 7
Erase element 8
Erase element 9
Erase element 10
Erase element 11
Erase element 12
Erase element 13
Erase element 14
Erase element 15
Erase element 16
Erase element 17
Erase element 18
Erase element 19
Erase element 20
Erase element 21
Erase element 22
Erase element 23

Program received signal SIGSEGV, Segmentation fault.
__memmove_ssse3_back () at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S:1548
1548    ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S: No such file or directory.
(gdb)
(gdb) where
#0  __memmove_ssse3_back ()
    at ../sysdeps/x86_64/multiarch/memcpy-ssse3-back.S:1548
#1  0x0000000000485d48 in std::__copy_move<true, true, std::random_access_iterator_tag>::__copy_m<Order> (__first=0x7fffe400e4a0, __last=0x7fffe400e470,
    __result=0x7fffe400e488) at /usr/include/c++/4.8/bits/stl_algobase.h:372
#2  0x00000000004807c4 in std::__copy_move_a<true, Order*, Order*> (
    __first=0x7fffe400e4a0, __last=0x7fffe400e470, __result=0x7fffe400e488)
    at /usr/include/c++/4.8/bits/stl_algobase.h:390
#3  0x000000000047879f in std::__copy_move_a2<true, __gnu_cxx::__normal_iterator<Order*, std::vector<Order, std::allocator<Order> > >, __gnu_cxx::__normal_iterator<Order*, std::vector<Order, std::allocator<Order> > > > (__first=...,
    __last=..., __result=...) at /usr/include/c++/4.8/bits/stl_algobase.h:428
#4  0x000000000046f9d3 in std::move<__gnu_cxx::__normal_iterator<Order*, std::vector<Order, std::allocator<Order> > >, __gnu_cxx::__normal_iterator<Order*, std::vector<Order, std::allocator<Order> > > > (__first=..., __last=...,
    __result=...) at /usr/include/c++/4.8/bits/stl_algobase.h:492
#5  0x0000000000467754 in std::vector<Order, std::allocator<Order> >::erase (
    this=0x6c7c10 <OrderList::sellOrders>, __position=...)
    at /usr/include/c++/4.8/bits/vector.tcc:138
#6  0x0000000000421320 in OrderList::flush () at ../Bether/OrderList.h:339
#7  0x000000000044b12a in main () at ../Bether/main.cpp:354

因此您可以看到 Vector 有 44 个元素 (SIZE: 44),但在应该删除第 23 个元素时失败。

【问题讨论】:

【参考方案1】:

std::vector::erase() 使迭代器无效,这意味着之后取消引用它 (*it) 或递增它 (++it) 是未定义的行为。

一个不错且常用的范例是结合std::remove_if(),它将要删除项移动到容器后面,以便std::vector::erase()实际删除它们:

std::vector<int> v =  0, 1, 2, 3, 4, 5, 6 ;
v.erase( std::remove_if(v.begin(), v.end(), [](int n) return n%2==0; ), v.end() );
// v is  1, 3, 5 

【讨论】:

@TommyA 错字已修复。谢谢。【参考方案2】:

erase 函数使指向已擦除位置之后的迭代器和引用无效。

如果你真的想删除它们,你可以改变循环以降序迭代,这应该没有问题,因为你使用的向量可以很容易地允许双向访问。这样,只有对已检查位置的引用才会失效。

【讨论】:

以上是关于Vector.erase 中的 SIGSEGV的主要内容,如果未能解决你的问题,请参考以下文章

VECTOR

C++ 分割在 vector.erase() 上失败

map, set, vector erase的正确使用方法

vector erase怎么用

map/vector erase

c++ vector erase的注意事项