0

How to deep erase a vector?

Consider the following code.

#include<algorithm>
#include<iostream>
#include<iterator>
#include<vector>

using namespace std;

int main(){
    vector<int> v {1,2,3,4,5};
    for_each(begin(v),end(v),[&v](int& n){
        static auto i = (int)0;
        if(n == 2){
            v.erase ( begin(v) +2, end(v));
        }
        cout << n << "  having index " << i++ << endl;
    });
    v.erase ( begin(v) +2, end(v));
    cout << v.size() << endl << v[4] << endl;
}

Output is

1  having index 0
2  having index 1
3  having index 2
4  having index 3
5  having index 4
2
4

What I want is accessing v[i] for any i from 2 to 4 to be invalid and compiler to throw an error.

In simpler words how to deep erase a vector?

kalpa
  • 657
  • 2
  • 11
  • 22

2 Answers2

1

You're triggering undefined behavior and therefore your results cannot be trusted.

If you need to check for boundaries use std::vector::at

vector<int> v{ 1,2,3,4,5 };
v.erase(begin(v) + 2, end(v));
try {
  auto val = v.at(4);
} catch (std::out_of_range&) {
  cout << "out of range";
}

Unless you code your own facility or workaround, you can't have such compile-time checks with std::vector. More information and some suggestions here: https://stackoverflow.com/a/32660677/1938163

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • What is the difference between accessing operator[] and at method? – kalpa Nov 18 '16 at 16:04
  • @kalpa `at` does bound checking and throws a runtime exception if out of range – Marco A. Nov 18 '16 at 16:05
  • Is it a bad practise to access vectors by using `[]`? – kalpa Nov 18 '16 at 16:15
  • @kalpa Absolutely not, plus it won't incur in additional overhead to do bounds checking.. but either you check for boundaries yourself (e.g. `i < v.size()`) or you use `at` not to stumble upon UB – Marco A. Nov 18 '16 at 16:16
  • thanks a lot for your time ... also can you refer me some sources of IB and UB of C++ std libraries if possible? – kalpa Nov 18 '16 at 16:19
  • @kalpa A good list and source of explanation can be found [here](http://en.cppreference.com/w/cpp/language/ub). Good luck! – Marco A. Nov 18 '16 at 16:20
1

I do not have time right now to give examples, but the only way I can think to cleanly do this is to either make a custom class to wrap or subclass vector. You could then produce a custom [] and at operators which throw an error on certain indexes. You could even have a deletion method which adds indeces to this list of banned ones.

Now if you need the error at compile time this is harder. I think something might be possible using a constexpr access operator and some static_asserts but I am not confident exactly how off hand.

Vality
  • 6,577
  • 3
  • 27
  • 48
  • If `operator[]` yields UB and does not do range checks then why is it permitted ? Also does `at` add a performance overhead compared to `operator[]`? If yes, how much significant is it? – kalpa Nov 18 '16 at 16:12
  • @kalpa The second sentence of your comment answers the first, [] exists as at is slow, exactly how slow depends but I would guess between 3-10 times as long to run. – Vality Nov 18 '16 at 16:28
  • another thing when I call `erase` or `clean` method is memory deallocated or is it not deallocated until the entire vector is destroyed? – kalpa Nov 18 '16 at 16:47
  • @kalpa It is not specified if the memory is deallocated at that time at that point or not, it depends on your compiler and stdlib. However remember erase shifts all the elements left to fill the empty spaces I think, so wont result in gaps. – Vality Nov 18 '16 at 16:52