How to search for an element in a vector? - c++

i have a code like this....
std::vector<string>::iterator p;
p = find(v.begin(),v.end(),"asdasda");
cout << *p << endl;
if "asdasda" is not a part of the vector, p points to some garbage and cout gives a seg fault. what should be the if statement that would make the cout execute onlyif "asdasda" was found?
and also the position of "asdasda" in v.. like if we had earlier declared v[3] as "asdasda",
then how can i know from the find that v[3] is "asdasda"?

p doesn't point to "garbage", it simply becomes v.end() when the content is not found.
if (p != v.end()) {
std::cout << "v[" << (p - v.begin()) << "] = ";
std::cout << *p << std::endl;
}

If std::find doesn't find anything, the iterator is set to v.end() in this case.
if ( p != v.end() )
{
// iterator is good
}
Also note the general case of std::find.
Here's a typical definition of it:
namespace std {
template <class InputIterator, class T>
InputIterator find(InputIterator start,
InputIterator finish,
const T& value);
}
In case std::find fails, it will return the finish iterator because the search is [start, finish) and includes start but excludes finish.

Find returns the end iterator if it doesn't find the value you search.
You can avoid your error by adding if (p != v.end()) right before your display line.

Related

How to handle std::find_if() returning false?

Take the following example taken from the cplusplus.com reference page and altered to return false:
// find_if example
#include <iostream> // std::cout
#include <algorithm> // std::find_if
#include <vector> // std::vector
bool IsOdd (int i) {
return ((i%2)==1);
}
int main ()
{
std::vector<int> myvector;
myvector.push_back(10);
myvector.push_back(20);
myvector.push_back(40);
myvector.push_back(50);
std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
std::cout << "The first odd value is " << *it << '\n';
return 0;
}
Since no value in myvector is odd it will return InputIterator last, which is undefined:
The first odd value is -1727673935
What is the proper way to handle this output?
How can I know std::find_if() returned false if the output is unpredictable and comparing to the entire vector to confirm the resulting value doesn't exist defeats the purpose of using std::find_if() to begin with?
Do you mean
std::vector<int>::iterator it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
if ( it != myvector.end() )
{
std::cout << "The first odd value is " << *it << '\n';
}
else
{
// std::cout << "there is no odd value in the vector\n";
}
The idiomatic way to do this is to check whether the iterator equals the end sentinel.
auto it = std::find_if (myvector.begin(), myvector.end(), IsOdd);
if (it == myvector.end()) {
std::cout << "No odd values found" << std::endl;
} else {
std::cout << "The first odd value is " << *it << std::endl;
}
In C++17 (the most recent standard), you can declare the iterator right in the if statement:
if (auto it = std::find_if(myvector.begin(), myvector.end(), IsOdd); it != myvector.end()) {
std::cout << "The first odd value is " << *it << std::endl;
} else {
std::cout << "No odd values found" << std::endl;
}
You need to check if the returned iterator is the end iterator you passed to std::find_if (the second argument). These semantics are quite common for algorithms in the standard library, so you should get used to this.
const auto firstOdd = std::find_if (myvector.cbegin(), myvector.cend(), IsOdd);
if (firstOdd != myvector.cend())
std::cout << "The first odd value is " << *it << '\n';
else
std::cout << "No odd values found\n";
Note also that you can use the cbegin()/cend() member functions, as you're not mutating the container.
std::find_if returns(reference cppreference.com)
Iterator to the first element satisfying the condition or last if no
such element is found.
That means, dereference the iterator only when its not equal to container.end() iterator.
if (const auto iter = std::find_if(myvector.cbegin(), myvector.cend(), IsOdd); // need C++17 compiler support
iter != myvector.cend())
{
std::cout << *iter << "\n";
}
else
{
// code
}
PS: In modern C++, lambdas expressions should be your good friends, and use it when it is appropriate.
See more here: Why can lambdas be better optimized by the compiler than plain functions?
That means your IsOdd could have been
constexpr auto isOdd = [](const int i) /* noexcept */ { return i & 1; };

Erasing pointers from vector while iterating another vector

I have tried many other similar questions but none of them helped me. My problem is as following:
I have 3 vectors of pointers to my struct: vector<state*>where state is my kind of struct. What I am trying to do is to remove states from vectorCheck if they are in either vectorOpen or vectorClosed. The point is, it sometimes works fine and sometimes not. According to CodeBlocks this seems to be a problem but I have no idea to overcome this. I debugged my program step by step and at some point, state from vectorCheck is not being removed despite of the fact it is in vectorClosed.
Iterating is held by 2 for loops:
vector<state*> vectorOpen;
vector<state*>::iterator itOpen;
vector<state*> vectorClosed;
vector<state*>::iterator itClosed;
vector<state*> vectorCheck;
vector<state*>::iterator itCheck;
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end(); itCheck++) {
for(itOpen = vectorOpen.begin(); itOpen != vectorOpen.end(); itOpen++) {
if ((*itCheck)->player->x == (*itOpen)->player->x &&
(*itCheck)->player->y == (*itOpen)->player->y &&
(*itCheck)->box[0].x == (*itOpen)->box[0].x &&
(*itCheck)->box[0].y == (*itOpen)->box[0].y) {
cout << "erasing as in open " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
vectorCheck.erase(itCheck);
}
}
}
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end(); itCheck++) {
for(itClosed = vectorClosed.begin(); itClosed != vectorClosed.end(); itClosed++) {
if((*itCheck)->player->x == (*itClosed)->player->x &&
(*itCheck)->player->y == (*itClosed)->player->y &&
(*itCheck)->box[0].x == (*itClosed)->box[0].x &&
(*itCheck)->box[0].y == (*itClosed)->box[0].y) {
cout << "erasing as in closed " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
vectorCheck.erase(itCheck);
}
}
}
Where vectorCheck is a maximum size of 3. To explain what I mean here is the picture
Where I am talking here about states in green rectangulars (3 1 2 4). Why isn't it being removed like the state in blue rectangular (2 2 2 4)? It should be removed as this state has appeared already in vectorClosed (code above).
What am I doing wrong? This is not the first iteration of the program, it happens in like 6th or 7th loop.
Also, this is probably causing my program to crash later on.
As mentioned in my comment, the problem is that you are continuing to use an iterator to an element you erased. std::vector::erase(i) is invalidating the itCheck iterator.
We can fix this by taking advantage of C++ algorithms like std::remove_if. It may make the code appear more complex at first glance, but you'll find this style of coding lets you reuse pieces of logic, improving the readability and maintainability of your code.
To start, let's write a functor that does the equality comparison you need.
struct states_are_equal :
public std::binary_function<state const *, state const *, bool>
{
bool operator()(state const * a, state const * b) const {
return a->player->x == b->player->x &&
a->player->y == b->player->y &&
a->box[0].x == b->box[0].x &&
a->box[0].y == b->box[0].y;
}
};
Now we need a predicate that will return true if the given item is found within another container. This part admittedly may be a bit hard to follow if you are not familiar with the algorithms library.
template <typename Iterator, typename Comparer>
struct is_in_container_func :
public std::unary_function<
typename std::iterator_traits<Iterator>::value_type const &,
bool
>
{
is_in_container_func(Iterator begin, Iterator end, Comparer cmp)
: it_begin(begin), it_end(end), comparer(cmp) { }
bool operator()(argument_type i) const {
return std::find_if(it_begin, it_end, std::bind1st(comparer, i)) != it_end;
}
private:
Iterator it_begin;
Iterator it_end;
Comparer comparer;
};
// This is just a helper to allow template type deduction; its only purpose is to
// allow us to omit the types for Iterator and Comparer when constructing an
// is_in_container_func object.
template <typename Iterator, typename Comparer>
is_in_container_func<Iterator, Comparer> is_in_container(
Iterator begin, Iterator end, Comparer cmp)
{
return is_in_container_func<Iterator, Comparer>(begin, end, cmp);
}
Now we can put all of these pieces together with std::remove_if:
std::vector<state*> vectorOpen;
std::vector<state*> vectorClosed;
std::vector<state*> vectorCheck;
// Make one pass, removing elements if they are found in vectorOpen.
std::vector<state*>::iterator new_end = std::remove_if(
vectorCheck.begin(), vectorCheck.end(),
is_in_container(vectorOpen.begin(), vectorOpen.end(), states_are_equal()));
// Make another pass, removing elements if they are found in vectorClosed.
new_end = std::remove_if(
vectorCheck.begin(), new_end,
is_in_container(vectorClosed.begin(), vectorClosed.end(), states_are_equal()));
// std::remove_if just swaps elements around so that the elements to be removed are
// all together at the end of the vector, and new_end is an iterator to the first
// one. So, finally, we just need to remove the range [new_end, end()).
vectorCheck.erase(new_end, vectorCheck.end());
The erase call invalidates the iterator passed to it. It shifts the elements in the vector one place to their left, and returns an iterator to the element after the removed one. Therefore, you should not increment the iterator if the erase was executed. Like so:
for(itCheck = vectorCheck.begin(); itCheck != vectorCheck.end();) { // no increment
bool found = false;
for(itOpen = vectorOpen.begin(); itOpen != vectorOpen.end(); itOpen++) {
if ((*itCheck)->player->x == (*itOpen)->player->x &&
(*itCheck)->player->y == (*itOpen)->player->y &&
(*itCheck)->box[0].x == (*itOpen)->box[0].x &&
(*itCheck)->box[0].y == (*itOpen)->box[0].y) {
cout << "erasing as in open " << (*itCheck)->player->x << " " << (*itCheck)->player->y << " " << (*itCheck)->box[0].x << " " << (*itCheck)->box[0].y << endl;
itCheck = vectorCheck.erase(itCheck);
found = true;
break; // found element and erased it. back to outer loop
}
}
if (!found) ++itCheck; // didn't find it, need to increment
}

Does the C++ std::binary_search() and then std::lower_bound() combo mean I am doing a binary search twice?

In my search for finding an element quickly in a vector using binary search, I found the std::binary_search function but then realized it only returns a bool, much to my dismay.
But then I found the most common solution to finding an element this way is to pair binary_search() with lower_bound(). After looking at it closer, I think that lower_bound() also searches for the element using a binary search esque situation. So, doesn't that mean I am searching for it twice?
This is an example of what I am referring to:
std::vector haystack{ 1, 3, 4, 5, 9 };
int needle = 5;
if (std::binary_search(haystack.begin(), haystack.end(), needle)) {
std::cout << "Found " << needle << '\n';
std::vector<int>::iterator it = lower_bound(haystack.begin(), haystack.end(), needle);
int result = *it;
cout << "Result " << result << endl;
}
Am I just doing this the wrong way? Is there another way I can binary search for something within a vector and get the actual found element?
Yes, you are doing two binary searches. Just use lower_bound once with an extra comparison:
auto it = std::lower_bound(haystack.begin(), haystack.end(), needle);
if (it != haystack.end() && *it == needle) {
// found it, here.
}
But only do that if you need the iterator. If you just want to check for the existence of needle, I would use std::binary_search() for added clarity for your users. Which could very well be implemented in terms of lower_bound to begin with. From cppreference:
template<class ForwardIt, class T>
bool binary_search(ForwardIt first, ForwardIt last, const T& value)
{
first = std::lower_bound(first, last, value);
return (!(first == last) && !(value < *first));
}
Yes, this is doing duplicate work. You can use std::lower_bound even if you're not sure whether the element is in the collection or not; if it isn't, it'll return the end iterator. You can therefore use the following:
auto it = lower_bound(haystack.begin(), haystack.end(), needle);
if (it != haystack.end() && *it == needle) {
cout << "Found " << needle << '\n';
cout << "Result " << *it << '\n';
}
Suppose needle is in the haystack. Then certainly needle will be the first element that is not less than needle, and so you will find it.
If needle is not in the haystack, and all elements are less than needle, then the end iterator will be returned and the it != haystack.end() check will fail.
If there is an element less than needle then an iterator it to it will be returned, but the check *it == needle will fail.
Either way, you get the desired result.

Expected return of find STL algorithm

list< int > a;
list < int > ::iterator it;
it = a.begin();
it=a.insert(it,10);
it=a.insert(it,210);
it=a.insert(it,310);
it=a.insert(it,410);
it=a.insert(it,510);
it = find(a.begin(),a.end(),180);
cout << *it << endl;
In this program the value 180 is not present in this list. So as per the find STL algorithm it should return the last value, but when I print this value it is coming something garbage. Seems like the iterator is pointing to some other location. Please help me spot my error.
a.end() is not an iterator to the last value but an iterator that is past the last element in the list. It should never be printed or accessed in any way. In the case of std::find, you should compare the return value to the end iterator. If it matches, there is no element in that container that matches the requested value.
it = find(a.begin(),a.end(),180);
if( a.end() == it ) { // using Yoda conditional
cout << "no element matching value.." << endl;
} else {
cout << *it << endl;
}
std::find returns end() if element is not found in STL container, dereference end() is undefined behavior.
You need to test iterator it before dereference it:
it = find(a.begin(), a.end(), 180);
if (it != a.end())
{
cout << *it << endl;
}
ยง 25.2.5
Returns: The first iterator i in the range [first,last) for which the following corresponding conditions hold: *i == value, pred(*i) != false, pred(*i) == false. Returns last if no such iterator is found.
range [first,last) is half open range, last means end() not last element in container.

std::list reverse iterating & erasing causes crash

I am traversing an std::list using reverse iterators and erasing some elements from the list using their forward iterators that were obtained when inserting them. A sample program is shown below. I read that deleting elements from a list doesn't invalidate other iterators except for the ones referring to element that's deleted. But there's no mention of reverse_iterators and my program is crashing. Can someone please tell if the usage is incorrect?
What the program is doing is adding an element into the list, storing its iterator, reverse iterating the list and deleting the only element in the list using its stored iterator.
The output is pasted below the code sample.
#include <list>
#include <iostream>
using namespace std;
struct node
{
int data;
list<node*>::iterator iter;
} a;
int main()
{
list<node*> l;
a.data = 1;
l.push_front( &a );
a.iter = l.begin();
list<node*>::reverse_iterator ri = l.rbegin();
while ( ri != l.rend() )
{
cout << (*ri)->data << endl;
list<node*>::reverse_iterator rj = ri;
++ri;
if ( ri == l.rend() )
cout << "before erase: reached end" << endl;
l.erase((*rj)->iter);
if ( ri == l.rend() )
cout << "after erase : reached end" << endl;
else
cout << "after erase : Not reached end" << endl;
}
}
OUTPUT
1
before erase: reached end
after erase : Not reached end
610568524
before erase : reached end
Segmentation fault
Under VS2010 it will throw an exception here, on the first loop pass:
l.erase((*rj)->iter);
if ( ri == l.rend() ) // exception
That should give you a general idea what's going on. You see, reverse_iterator is just a wrapper for standard iterator. That said, you should remember that it's got base() member that returns underlying iterator - you don't have to store it elsewhere, like you do in node struct.
Here's a great answer to how reverse_iterator relates to the iterator. In your case, rbegin will be based on begin iterator. If you remove the begin from the list (which you do, since it has only one element), all reverse_iterators based on this iterator will become invalid. Keeping that in mind you could rewrite your loop the following way:
while ( ri != l.rend() )
{
cout << (*ri)->data << endl;
list<node*>::reverse_iterator rj = ri;
++ri;
if ( ri == l.rend() )
cout << "before erase: reached end" << endl;
// the actual underlying iterator has an offset of one
list<node*>::iterator it = l.erase(--rj.base());
ri = reverse_iterator<list<node*>::iterator>(it);
// or just
// ri = reverse_iterator<list<node*>::iterator>(l.erase(--rj.base()));
if ( ri == l.rend() )
cout << "after erase : reached end" << endl;
else
cout << "after erase : Not reached end" << endl;
}
The reverse iterator is (tpyically) not a unique class, but a adapter on a normal iterator - it has a iterator into a list as member and uses it to do its own moving and dereferencing. So when this list iterator gets invalidated, the reverse iterator is invalidated too.
i'm writing an answer to note my findings; if you hit this problem try
SingerOfTheFall 's suggested method, it works like a charm, example:
for(auto it=values.end();it!=values.begin();){
if((*it).second.endPoint)
break;
values.erase((*(it--)).first);
}
back to my findings about this:
when i hit the problem the program hanged, and i've run a valgrind check, it dropped out some strange Invalid reads originated from libstdc++
Invalid read of size 8
at 0x4EAA633: ??? (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.20)
by 0x402FEC: std::_Rb_tree_iterator<std::pair<int const, GroupControl::Group::Entry> >::operator--() (stl_tree.h:218)
i suspect that after the last element's erase the rend() doesnt stop the iterator, and the ++ op is trapped in a loop
You need store erase return value into iterator. Do following change.
(*rj)->iter= l.erase((*rj)->iter);