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.
Related
What is the best method to return the last element in a container that does not provide a back() member function, such as std::set?
Since the end() method returns an iterator to the first element after the end of the container, is the only way of grabbing the last element to decrement the iterator before dereferencing it?
Such as:
std::set<int> set = {1,2,3,4,5};
int end = *(set.end());
int beforeEnd = *(--set.end());
std::cout << "set.end() -> " << end << std::endl;
std::cout << "--set.end() -> " << beforeEnd << std::endl;
However, these both return:
set.end() -> 5
--set.end() -> 5
Is this the proper way of getting the last element, and why do these return the same value?
This
int end = *(set.end());
As commented by πάντα ῥεῖ, has undefined behavior. That's because std::set::end
Returns an iterator to the element following the last element of the container. This element acts as a placeholder; attempting to access it results in undefined behavior.
(https://en.cppreference.com/w/cpp/container/set/end, emphasis mine)
The other line:
int beforeEnd = *(--set.end());
It's not guarateed to work. See e.g. https://en.cppreference.com/w/cpp/iterator/prev, emphasis mine:
Although the expression --c.end() often compiles, it is not guaranteed to do so: c.end() is an rvalue expression, and there is no iterator requirement that specifies that decrement of an rvalue is guaranteed to work. In particular, when iterators are implemented as pointers, --c.end() does not compile, while std::prev(c.end()) does.
So it may fail for the same reason that this wouldn't compile:
int arr[4] = {1,2,3,4};
int *p = --(arr + 4); // --> error: expression is not assignable
You can write something like the following, instead.
std::set<int> set = {1,2,3,4,5};
if ( set.begin() != set.end() )
{
auto itLast = std::prev(set.end());
std::cout << "last -> " << *itLast << '\n';
}
Is the only way of grabbing the last element to decrement the iterator
before dereferencing it?
No, there are also other options.
The simplest way is using the reverse iterators(both std::set::rbegin or std::set::crbegin), which dirctly give you the element which is one past std::sets end iterator.
From cppreference.com, std::set::rbegin and std::set::crbegin
Returns a reverse iterator to the first element of the reversed
container. It corresponds to the last element of the non-reversed
container. If the container is empty, the returned iterator is equal
to rend().
std::set<int> set = { 1,2,3,4,5 };
auto iter = set.rbegin();
const int beforeEndIter = *iter;
std::cout << "--set.end() -> " << beforeEndIter << '\n';
(update) in case of the second last element in the container(i.e. two past the end iterator), use std::next for the same reason mentioned in the other answer for std::prev. See a demo
std::set<int> set = {1, 2};
const bool hasElements = set.cbegin() != set.cend();
auto iter = set.rbegin();
if(hasElements && iter != set.rend()) std::cout << "--set.end() -> " << *iter << '\n';
if(hasElements && std::next(iter) != set.rend()) std::cout << "two past set.end() -> " << *std::next(iter) << '\n';
outputs:
--set.end() -> 2
two past set.end() -> 1
The second option has been mentioned in the other answer.
On the other hand, dereferencing the end iterator is an undefined behavior, in which you could expect any result. In your case, you have got the last element(i.e. one past end iterator) of the container.
For the below sample program, the lower_bound is generating core dump. Any idea where could be the mistake ?
Also, can anyone please explain how the lower_bound and upper_bound algorithm works in c++?
#include <iostream>
#include <map>
int main ()
{
std::map<int,int> mymap;
std::map<int,int>::iterator itlow,itup;
mymap[100]=10;
mymap[1000]=20;
mymap[2000]=40;
mymap[3000]=60;
mymap[4000]=80;
mymap[5000]=100;
itlow=mymap.lower_bound (2001);
itup=mymap.upper_bound (1500);
std::cout<<(itlow->first)<<std::endl;
std::cout<<(itup->first)<<std::endl;
mymap.erase(itlow,itup); // erases [itlow,itup)
// print content:
for (std::map<int,int>::iterator it=mymap.begin(); it!=mymap.end(); ++it)
std::cout << it->first << " => " << it->second << '\n';
return 0;
}
You have the erase backwards:
mymap.erase(itup, itlow); // erases [itlow,itup)
You can erase only from a smaller iterator to a iterator following the first parameter. In this case your iterators point to the values:
lower: 3000
upper: 2000
and itup < itlow
from lower_bound and upper_bound
lower_bound returns:
Returns an iterator pointing to the first element in the range
[first,last) which does not compare less than val.
upper_bound returns:
Returns an iterator pointing to the first element in the range
[first,last) which compares greater than val.
My understanding is the iterators of associative containers are not invalidated during insert or erase (unless the node pointed by iterator is erased). But in the below program
the insert seems to invalidate the iterator. Is my understanding wrong?
typedef std::set<unsigned int> myset_t;
int main(int argc, char **argv)
{
myset_t rs;
myset_t::reverse_iterator rit;
myset_t::reverse_iterator srit;
int ii = 500;
rs.insert(10);
rs.insert(11);
rs.insert(12);
rs.insert(13);
rs.insert(14);
rs.insert(100000);
rs.insert(102000);
rs.insert(103000);
rit = rs.rbegin();
while(rit != rs.rend()) {
srit = rit;
if (*rit < 100000) {
cout << "bailing here " << *rit << endl;
return 0;
}
rit++;
cout << "Before erase " << *rit << endl;
rs.erase(*srit);
cout << "Before insert " << *rit << endl;
rs.insert(ii);
cout << "After insert " << *rit << endl;
ii++;
}
cout << "Out of loop" << endl;
}
===
The output is
Before erase 102000
Before insert 102000
After insert 14
bailing here 14
=====
The promised behavior for iterators of a standard container does not hold for reverse iterators of that container.
A reverse iterator actually stores, as a member, the normal (forward moving) iterator which comes after the element to which the reverse iterator refers when dereferenced. Then when you dereference the reverse iterator, essentially it decrements a copy of this stored normal iterator and dereferences that. So this is a problem:
rit = rs.rbegin(); // rit stores rs.end()
srit = rit; // srit also stores rs.end()
rit++; // rit stores a normal iterator pointing to the last element
rs.erase(*srit); // this deletes the last element, invalidating the normal
// iterator which is stored in rit. Funnily enough, the
// one stored in srit remains valid, but now *srit is a
// different value
Reverse iterators behave this way because there is no "before begin" iterator. If they stored the iterator to the element to which they actually refer, what would rs.rend() store? I'm sure there are ways around this, but I guess they required compromises which the standards committee was not willing to make. Or perhaps they never considered this problem, or didn't consider it significant enough.
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);
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.