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?
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
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.
Related
cin >> q;
while (q--)
{
cin >> data;
//if this value is greater than all the elements of the vector throwing error
vector<int>::iterator low = lower_bound(v.begin(), v.end(), data); //does the lower bound
if (v[low - v.begin()] == data)
cout << "Yes " << (low - v.begin() + 1) << endl;
else
cout << "No " << (low - v.begin() + 1) << endl;// while this should be the output
}
if vector v contains 1 2 3 4 5 6 7 8
and we enter data 9
then its showing error as vector subscript out of range.
Per the std::lower_bound() documentation on cppreference.com:
Returns an iterator pointing to the first element in the range [first, last) that is not less than (i.e. greater or equal to) value, or last if no such element is found.
In your call to lower_bound(v.begin(), v.end(), data), when v is {1 2 3 4 5 6 7 8} and data is 9, there is no element in v that is >= data, so v.end() gets returned to low. As such, low - v.begin() is v.end() - v.begin(), which produces an index (8) that is out of bounds of the vector (valid indexes are 0-7). Which Visual Studio then warns you about.
You need to add a check for the condition when std::lower_bound() does not find a matching element:
auto low = lower_bound(v.begin(), v.end(), data);
if (low == v.end()) // <-- ADD THIS!
{
cout << "Not found" << endl;
}
else
{
auto index = low - v.begin();
if (v[index] == data)
cout << "Yes " << (index + 1) << endl;
else
cout << "No " << (index + 1) << endl;
}
Receiving “vector subscript out of range” only on visual studio ...
Visual Studio is correct in giving that assertion.
The debug version of the Visual C++ runtime will check the indices of std::vector, and will report issues if there is an out-of-bounds access.
The other compiler you're using is not reporting this error to you, since in reality operator [] for std::vector has undefined behavior if accessing an out-of-bounds item. Thus you are mistaken when you see the output -- your program has an off-by-one bug.
To prove this, here is your code, but it uses at() instead of [ ] to access the elements:
#include <vector>
#include <iostream>
int main()
{
std::vector<int> v = {1,2,3,4,5,6,7,8};
std::vector<int>::iterator low = lower_bound(v.begin(), v.end(), 9);
if (v.at(low - v.begin()) == 9)
std::cout << "Yes " << (low - v.begin() + 1) << std::endl;
else
std::cout << "No " << (low - v.begin() + 1) << std::endl;// while this should be the output
}
Live Example
Note the std::out_of_range exception? You will now get that same error, regardless of the compiler you will use, since vector::at() does bounds checking.
Now here is your original code:
Original code
Note that you get the output, but you are "silently" accessing an out-of-bounds element, thus the behavior of the program is undefined.
What's the best way to select individual elements from a C++ std::vector?
I'm used to C-style arrays and this is the first time I'm using vectors.
I'm looking for something like:
std::vector<std::string> myvector;
astring = myvector[1];
bstring = myvector[3];
cstring = myvector[10];
And so on.
There are several ways to access elements in a std::vector:
myVector[3] - access the 4th element (0-indexed).
myVector.at(3) - access the 4th element with bounds checking. Throws an exception if the index is not less than the number of elements.
iterating over all elements with the standard algorithms: std::find(std::begin(myVector), std::end(myVector), 10).
Personally I've never found a use for at(), since I keep track of the index that I'm using anyway. I rarely just take a number from somewhere and stick it into [].
But be aware that accessing an index not less than the number of elements using [] is Undefined Behaviour (if the vector has 4 elements, you access them with 0, 1, 2, and 3). You are expected to be sure it is safe yourself. So in your example, this would be illegal, since you don't put anything into the vector first.
You ask for the best way... The answer is: There is no general best way
The best way is not always the same. It really depends on what your code is doing.
The best way also depends on what you want to achieve, e.g. best performance, best code maintainability, best code readability and so on.
The best way is also based on a personal view.
So just to repeat the answer: There is no general best way
Other answers mentions a number of different posibilities. I'll add one more.
// To iterate over all elements in a vector you can do
for (auto& e : someVector)
{
// Do something with e, e.g. print it
cout << e;
}
There are three general ways to access elements of a vector.
The first one is similar to accessing elements of an array using the subscript operator [].
For example
std::vector<std::string> v = { "Hello", "World" };
std::cout << v[0] << ' ' << v[1] << std::endl;
The second one is to use iterators similar to using pointers. For example
std::vector<std::string> v = { "Hello", "World" };
auto it = v.begin();
std::cout << *it << ' ' << *( it + 1 ) << std::endl;
The third one is to use member function at that checks the boundaries of a vector and throws an exception when an attempt is made to access memory beyond the vector
std::vector<std::string> v = { "Hello", "World" };
std::cout << v.at( 0 ) << ' ' << v.at( 1 ) << std::endl;
Also there are methods to acess the first and the last elements of a vector
for example
std::vector<std::string> v = { "Hello", "World" };
std::cout << v.front() << ' ' << v.back() << std::endl;
To access sequentially all elements of a vector you can use three kinds of loops.
For example
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( int x : v ) std::cout << x << ' ';
std::cout << std::endl;
or
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( std::vector<int>::size_type i = 0; i < v.size(); i++ ) std::cout << v[i] << ' ';
std::cout << std::endl;
or
std::vector<int> v = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for ( auto it = v.begin(); it != v.end(); ++it ) std::cout << *it << ' ';
std::cout << std::endl;
Simple use operator[] as you do with arrays. If you want boundary checking use at().
That is generally how you access vectors, they were made to be similar to arrays using the indexing operator.
However, once you when you declare a vector like you do, without passing any arguments to the constructor the vector is empty, which means that any indexing will be out of bounds and you will have undefined behavior.
If you want to specify an initial size, you could pass an argument to the constructor:
std::vector<std::string> myvector(11); // Creates a vector of 11 elements
If you never will change the size of the vector, if the size is fixed at the time of compilation using a compile-time constant, then you should probably be suing std::array instead:
std::array<std::string, 11> myarray;
You can access (i.e. select some element) a std::vector similar to C-style arrays i.e. by using indexes. Similar to arrays, no bound checking is performed in case of std::vector as well when you access some element which is not present. For example, you have inserted 10 elements in vector v but accessing 200th element using v[200] - but it could result undefined behavior, so be careful.
This question already has answers here:
C++ Erase vector element by value rather than by position? [duplicate]
(4 answers)
Closed 7 years ago.
I would like to modify a member function of the vector class. Is this possible? For example I would like to be able to delete with respect to value, and not the integer of the vector.
I think this does what you are looking for. This example removes all the occurrences of the number 6 from a vector using std::remove. xs.erase is to make sure the vector removes the elements and shrinks the vector to the new size.
I generally avoid modifying the STL containers as the people who implemented them are likely far smarter than me when it comes to this kind of thing. I recommend you learn the standard library algorithms, there generally is one suited to most kinds of general container operations.
#include <iostream>
#include <algorithm>
int main(int argc, char** argv)
{
std::vector<int> xs{1, 3, 6, 2, 6, 5};
std::cout << "xs size: " << xs.size() << std::endl; // xs.size() == 6
auto value_to_remove = 6;
xs.erase(std::remove(xs.begin(), xs.end(), value_to_remove), xs.end());
for (const auto& x : xs)
std::cout << x << ", ";
std::cout << std::endl; // 1, 3, 2, 5,
std::cout << "xs size: " << xs.size() << std::endl; // xs.size() == 4
return 0;
}
In this case, as with most other STL algorithms value_to_remove can be replaced with a (unary) lambda predicate opening up a whole world of exotic value finding.
You could wrap the above in a function as follows:
template <typename T>
void erase_by_value(std::vector<T>& xs, const T& value_to_remove)
{
xs.erase(std::remove(xs.begin(), xs.end(), value_to_remove), xs.end());
}
I have some difficulties in understanding the behaviour of the C++ clear function, when applied to a vector.
I tried to compile and run the following function:
#include <iostream>
#include <vector>
using namespace std;
int main ()
{
unsigned int i;
vector<int> myvector;
myvector.push_back (1);
myvector.push_back (2);
myvector.push_back (3);
cout << "myvector contains:";
for (i=0; i<myvector.size(); i++) cout << " " << myvector[i];
myvector.clear();
myvector.push_back (11);
myvector.push_back (12);
cout << "\nmyvector contains:";
for (i=0; i<myvector.size(); i++) cout << " " << myvector[i];
cout << endl;
cout << " entry3 = " << myvector[2]<<endl;
return 0;
}
And this is the output:
myvector contains: 1 2 3
myvector contains: 11 12
entry3 = 3
How is it possible that the information of the third entry of the vector has not been erased when clearing the vector?
From the docs:
All the elements of the vector are dropped: their destructors are called, and then they are removed from the vector container, leaving the container with a size of 0.
Basically you're invoking undefined behavior on myvector[2] because that item no longer exists. You only pushed 2 elements in the vector after calling clear(), so only indices 0 and 1 are accessible.
You're unlucky that it didn't crash, because appearing to work can hide bugs. There's no guarantee that the value is erased.
Trying to access the element with .at(2) instead will result in an exception being thrown (operator[]() doesn't do any bound-checking, whereas at() does).
If you attempt to run this code in debug mode, it's likely it will crash with a debug assertion. Referencing past the end of an array is undefined behaviour.
What's actually happening is that vector has not wiped the memory it was previously using before you ran clear(). This memory is still present but it's not defined what will happen if you access it. It's up to you to perform bounds checking to avoid running off the end of a vector. You can do this by looping with size() as a bounds, or by using at() and catching the out_of_range exception. I wouldn't particularly recommend this latter approach since it's not a good idea to use exceptions for runtime checks.
Given the following code:
// range heap example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
bool Greater(int a, int b)
{
if (a > b)
{
return true;
}
else
{
return false;
}
}
int main () {
int myints[] = {10,20,30,5,15};
vector<int> v(myints,myints+5);
//vector<int>::iterator it;
make_heap (v.begin(),v.end(), Greater);
cout << "initial min heap : " << v.front() << endl;
pop_heap (v.begin(),v.end(), Greater); v.pop_back();
cout << "min heap after pop : " << v.front() << endl;
v.push_back(9); push_heap (v.begin(),v.end(), Greater);
cout << "min heap after push: " << v.front() << endl;
sort_heap (v.begin(),v.end());
cout << "final sorted range :";
for (unsigned i=0; i<v.size(); i++) cout << " " << v[i];
cout << endl;
return 0;
}
why the return value is as follows:
initial min heap : 5
min heap after pop : 10
min heap after push: 9
final sorted range : 10 15 20 30 9 <= why I get this result, I expect 9 10 15 20 30.
If I call sort_heap(v.begin(), v.end(), Greater), then return value is 30 20 15 10 9.
Question > In this sample, I create a min-heap. Is this the reason that I cannot call sort_heap(v.begin(), v.end())?
thank you
sort_heap only sorts the range if it is heap-ordered according to the provided comparator. Since you used Greater as the comparator in all the heap operations, you don't have the elements in heap order according to the default comparator, so sort_heap isn't guaranteed to work correctly. The regular sort algorithm should work just fine, though.
You need to pass Greater to sort_heap as with all the other heap operations.
sort_heap (v.begin(),v.end(), Greater);
As #Blastfurnace mentions, std::greater<int>() is preferable to defining your own function. Besides the elegance factor, there is a performance issue: when you pass a function by reference for implicit conversion to a functor, it is first implicitly converted to a function pointer, which can result in less efficient execution due to an indirect branch instruction.