Bobface
Bobface

Reputation: 2952

SIGSEGV in Vector.erase

I'm getting a strange Segmentation fault error when I erase an element in a vector. This is the code:

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

The output is this:

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

So you can see the Vector has 44 elements (SIZE: 44) but fails when Element 23 should be deleted.

Upvotes: 0

Views: 1168

Answers (2)

YSC
YSC

Reputation: 40070

std::vector::erase() invalidates the iterator, meaning it is undefined behaviour to dereference it (*it) or increment it (++it) afterward.

A nice and usual paradigm is to combine std::remove_if() which moves the to be removed items in the back of the container for std::vector::erase() to actually remove them:

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 }

Upvotes: 6

Tommy Andersen
Tommy Andersen

Reputation: 7220

The erase function invalidates iterators and references pointing after the erased position.

If you really wanted to erase them you could alter the loop to iterate in decreasing order instead, this should be no trouble since you are using vectors which can easily allow bidirectional acces. In this way only the references to the locations already examined will be invalidated.

Upvotes: 3

Related Questions