C++ | List iterator not incrementable - c++

I am trying to iterate through a list and then, if the object's plate number matches the one given through the parameters, and if the toll (calculated in toll()) is less than or equal to the given cents, remove/erase the object from the list. I keep getting the error that the list iterator cannot be incremented and I'm clueless as to how to fix it.
void one_time_payment(string& plate_number, int cents) {
// TODO: REWRITE THIS FUNCTION
std::list<LicenseTrip>:: iterator it;
for (it = listLicense.begin(); it != listLicense.end(); std::advance(it, 1)) {
if (it->plate_number().compare(plate_number) == 0) {
cout << "Matching Plate Found" << endl;
if (it->toll() <= cents) {
cout << "Can be paid" << endl;
it = listLicense.erase(it); //Error: list iterator cannot be incremented
}
}
}
cout << "End of Iterator" << endl;
}

This is, I'm guessing, not a compile error but rather an assertion that triggered. You have a bug!
Let's say you're on the last element, and all your conditions apply. So we do:
it = listLicense.erase(it);
Now, it is end(). But right after that, at the end of the body of the for loop, we advance it! This is undefined behavior! Hence: list iterator cannot be incremented.
To help us write this correctly, there is a list::remove_if:
listLicense.remove_if([&](const LicenseTrip& trip){
return trip.plate_number() == plate_number &&
trip.toll() <= cents;
});

So, as Barry explained, the problem that was causing the failed assertion was that the iterator would attempt to advance it beyond end() which would give undefined behavior. In my case, the it would only be needed once (only used to locate a LicenseTrip with a matching plate_number), so it sufficed to put a break; after the listLicense.erase(it). The final working code is as follows:
void one_time_payment(string& plate_number, int cents) {
std::list<LicenseTrip>:: iterator it;
for (it = listLicense.begin(); (it != listLicense.end()) ; std::advance(it, 1)) {
if (it->plate_number().compare(plate_number) == 0 && it->toll() <= cents)
if (it->toll() <= cents) {
listLicense.erase(it);
break;
}
}
}

Related

Decrementing std::vector::iterator before std::vector::begin()

Following one of the "deleting while iterating" patterns on a vector, I don't understand why this code works, or if it's making use of undefined behavior:
The Code:
#include <vector>
#include <iostream>
int main(int argc, char* argv[], char* envz[])
{
std::vector<std::string> myVec;
myVec.push_back("1");
myVec.push_back("2");
myVec.push_back("3");
for (std::vector<std::string>::iterator i = myVec.begin();
i != myVec.end();
++i)
{
if ("1" == *i)
{
std::cout << "Erasing " << *i << std::endl;
i = myVec.erase(i);
--i;
continue;
}
std::cout << *i << std::endl;
}
return 0;
}
The Output:
>g++ -g main.cpp
>./a.out
Erasing 1
2
3
Question:
Consider the first iteration of the for-loop:
i is myVec.begin(), which "points to" 1.
We enter the conditional block.
1 is erased and i is set to one past the erased element, i.e. 2, which is now also pointed to by myVec.begin()
I decrement i, so now it points to...one prior to myVec.begin() ???
I'm confused by why this seems to work, as evidenced by the output, but something feels fishy about decrementing the iterator. This code is easy enough to rationalize if the conditional is if ("2" == *i), because the iterator decrement still places it at a valid entry in the vector. I.e. if we conditionally erased 2, i would be set to point to 3, but then manually decremented and thus point to 1, followed by the for-loop increment, setting it to point back to 3 again. Conditionally erasing the last element is likewise easy to follow.
What Else I Tried:
This observation made me hypothesize that decrementing prior to vector::begin() was idempotent, so I tried addition an additional decrement, like so:
#include <vector>
#include <iostream>
int main(int argc, char* argv[], char* envz[])
{
std::vector<std::string> myVec;
myVec.push_back("1");
myVec.push_back("2");
myVec.push_back("3");
for (std::vector<std::string>::iterator i = myVec.begin();
i != myVec.end();
++i)
{
if ("1" == *i)
{
std::cout << "Erasing " << *i << std::endl;
i = myVec.erase(i);
--i;
--i; /*** I thought this would be idempotent ***/
continue;
}
std::cout << *i << std::endl;
}
return 0;
}
But this resulted in a segfault:
Erasing 1
Segmentation fault (core dumped)
Can someone explain why the first code bock works, and specifically why the single decrement after erasing the first element is valid?
No, your code has undefined behaviour: if i == myVec.begin(), then i = myVec.erase(i); results in i again being (the new value of) myVec.begin(), and --i has undefined behaviour since it goes outside the valid range for the iterator.
If you don't want to use the erase-remove idiom (i.e. myVec.erase(std::remove(myVec.begin(), myVec.end(), "1"), myVec.end())), then the manual loop-while-mutating looks like this:
for (auto it = myVec.begin(); it != myVec.end(); /* no increment! */) {
if (*it == "1") {
it = myVec.erase(it);
} else {
++it;
}
}
Regardless, the crucial point both here and in your original code is that erase invalidates iterators, and thus the iterator must be re-assigned with a valid value after the erasing. We achieve this thanks to the return value of erase, which is precisely that new, valid iterator that we need.
This might work in some compilers, but might fail in others (e.g. the compiler might actually check in runtime that you are not decrementing under begin() and throw exception in such case - I believe that at least one compiler does it but don't remember which one).
In this case the general pattern is to not increment in the for but inside the loop:
for (std::vector<std::string>::iterator i = myVec.begin();
i != myVec.end();
/* no increment here */)
{
if ("1" == *i)
{
std::cout << "Erasing " << *i << std::endl;
i = myVec.erase(i);
continue;
}
std::cout << *i << std::endl;
++i;
}
With vector the wrong iteration might actually work in more cases, but you'd have very bad time if you try that e.g. with std::map or std::set.
The key here is the continue right after decrementing.
By calling it, ++i will be triggered by the loop iteration before dereferencing i.

how to use iterator in a recursive function

im studying c++ primer, and in one exercise, i have to do a recursive function that prints the elements on a vector.
I did this:
void printVector(vector<int>::iterator it1, vector<int>::iterator it2) {
cout << *it1 << " ";
if (it1 != it2-1)
printVector((it1 + 1), it2);
}
is there another form to declare it, without the
if(it1!= ***IT2-1***)
i feel like its a mediocre solution couse i cant find another way.
thanks!!
Your function does not accept empty range, which it should, and it is a good idea to put exit condition into begin of a recursive function:
void printVector(vector<int>::iterator it1, vector<int>::iterator it2)
{
if( it1 == it2 ) return;
cout << *it1++ << " ";
printVector(it1, it2);
}
Yes.
void printVector(vector<int>::iterator begin, vector<int>::iterator end)
{
if (begin != end) {
cout << *begin << " ";
printVector(++begin, end)(;
}
}
Yes, you probably want to go at it in another way. It is pretty silly to do recursion when a simple loop will do. Instead, recursion is a tool to use in a more divide an conquer style. I.e. divide into two parts, then apply the same function to the first part and then to the second part.
Usually you then have some kind of cutoff point as to when you can actually do whatever it is you want to do, say for instance that you have less than N number of elements to work with or similar. This example is pretty contrived, because it only brings overhead to do it recursively.
template<class Iter>
void printVector(Iter begin, Iter end)
{
const auto dist = std::distance(begin, end);
if (0 == dist) {
return;
} else if (1 == dist) {
std::cout << *begin;
} else {
// Find the middle
auto pivot = begin + dist/2;
// Apply to first part
printVector(begin, pivot);
// Print separator
std::cout << " ";
// Apply to second part
printVector(pivot, end);
}
}
Please forgive any typos and other issues. Oh, I made it a template as well so that it accepts any random access iterators. That was mostly because it felt annoying to type vector<int>::iterator twice. That should probably be vector<int>::const_iterator by the way.

Applying Greater than or Less than Checks to both Strings and Primitive Data Types?

I'm working on a project which requires that I create a template class for an Accumulator which returns weather or not the list passed to it is in order. The order is ascending.
I am probably overthinking the problem but I cannot seem to figure out how to do a greater than/ less than check on both primitive data types and strings. I'll clarify:
The process goes like this:
A list/vector is declared and stuff is stored in it.
Then a secondary Accumulator called apply is called.
This Accumulator(apply) iterates through the list calling the .put() method of the InOrder Accumulator on every value in the list. The values could be of type double, long, short, etc or string.
I have tried setting an arbitrary lower bound, setting it equal to the first element in the list and then doing checks based on that start point but this offers mixed results because it does not work on the strings.
I was thinking of checking typeid or something so that for strings I could then call the .size() method and compare that way. Were as for primitives I would simply use the > or < operator. But that would defeat the point of the template function. Any help would be greatly appreciated.
I'll post the Code were the function is called, the code for the Apply Accumulator, and my Code for InOrder. Let me know if anything else is required.
My InOrder:
template<typename T>
class InOrder
{
public:
InOrder(){}
~InOrder(){}
void put(T item)
{
_count++;
if(_count == 1)
{
_lowbound = item;
}
if(_count!=0 && _count!=1 && item<_lowbound)
{
_order = false;
}
if(_count!=0 && _count!=1 && item>_lowbound)
{
_order = true;
}
_count++;
}
bool get()
{
return _order;
}
private:
T _lowbound;
int _count = 0;
bool _order;
};
Apply Accumulator:
template<typename A, typename I>
void apply(A & anAccumulator, I begin, I end)
{
for (I iter = begin; iter != end; ++iter)
{
anAccumulator.put( *iter);
}
}
Code where InOrder is Called:
{
// Read a list of doubles into a List and check their order
cout << "apply InOrder to a List of doubles\n";
double sentinel = -1.23;
List<double> dList;
fillList(sentinel, dList);
InOrder<double> dblInOrder;
apply(dblInOrder, begin(dList), end(dList));
cout << "The doubles in dList are ";
if (!dblInOrder.get())
cout << "NOT ";
cout << "in order\n\n";
}
{
// Read a list of strings into a List and check their order
cout << "apply InOrder to a List of strings\n";
string strSent = "end";
List<string> sList;
fillList(strSent, sList);
InOrder<string> strInOrder;
apply(strInOrder, begin(sList), end(sList));
cout << "The strings in sList are ";
if (!strInOrder.get())
cout << "NOT ";
cout << "in order\n\n";
}
I should note that the the items put into the list are processed in the reverse order.
Eg: if I type my list in as [a,b,c] or [1,2,3] the first value/string to be processed will be c/3 and then so on for there to b/2 and a,1
Your mistake is that you do not stop when you detect that order is wrong:
_order = false; // here is you have to stop and skip all other items
This won't work:
if(_count!=0 && _count!=1 && item<_lowbound)
{
_order = false;
}
if(_count!=0 && _count!=1 && item>_lowbound)
{
_order = true;
}
because should be:
if(_count!=0 && _count!=1 && item<_lowbound)
{
_order = false;
}
Delete the second part, and add:
InOrder() : _order(true) {}
To your constructor.

Removing entries of particular key in C++ STL multimap

I have this sample code to insert entries to a multimap. I am trying to delete particular entries of a specified key. But this code goes into infinite loop. Can someone help me with this code?
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main()
{
multimap<string, string> names;
string n;
names.insert(pair<string, string>("Z", "F"));
names.insert(pair<string, string>("Z", "A"));
names.insert(pair<string, string>("S", "T"));
names.insert(pair<string, string>("S", "A"));
names.insert(pair<string, string>("S", "J"));
names.insert(pair<string, string>("D", "H"));
names.insert(pair<string, string>("D", "W"));
names.insert(pair<string, string>("D", "R"));
multimap<string, string>::iterator p;
p = names.find("Z");
if(p != names.end()) { // found a name
do {
cout << n << ", " << p->second;
cout << endl;
if (p->second.compare("A") == 0) {
names.erase(p);
p++;
} else {
p++;
}
} while (p != names.upper_bound("Z"));
}
else{
cout << "Name not found.\n";
}
p = names.find("Z");
if(p != names.end()) { // found a name
do {
cout << n << ", " << p->second;
cout << endl;
} while (p != names.upper_bound("Z"));
}
else{
cout << "Name not found.\n";
}
return 0;
}
In the above I am looking up using Key value "Z" and want to delete "A".
multimap::erase invalidates any iterators to the erase elements, so the lines
names.erase(p);
p++;
erases p, thus invalidating it, and then attempt to increment an invalid iterator. You can fix this by copying p to a temporary, incrementing p, and then erasing the temporary iterator.
multimap<string, string>::iterator temp = p;
++p;
names.erase(temp);
Alternatively if you're using C++11 then multimap::erase returns the next iterator in the container
p = names.erase(p);
Edit: the above isn't actually the source of your infinite loop. In the second loop you don't increment p, so it goes forever. However it is still something you should fix as it can cause unpredictable and difficult to track down bugs.
As said by others, advancing an iterator that points to an element that was just erased is not guaranteed to work. What you can do instead is to use the postfix ++ operator to retrieve an iterator to the element that followed the erased one before it was erased:
names.erase(p++);
In C++11, you can alternatively retrieve the return value of erase, which points to the following element (or is end() if there is no more element):
p = names.erase(p);
It has also been said already that your second loop is an infinite loop by definition because it never increments the counter.
However, there is one more thing that should be said: Your method of checking if the last element in a range of elements has been reached is not very efficient: You call upper_bound in every iteration of the loop, which will cause a new O(log(n)) tree search each time, although the iterator returned will always be the same.
You can obviously improve this by running upper_bound before you enter the loop and store the result. But even better, I'd suggest your run the equal_range function once, and then simply iterate through the range it returned:
typedef multimap<string,string>::const_iterator mapit;
std::pair<mapit,mapit> range = names.equal_range("Z");
mapit it = range.first;
while (it != range.second)
if (it->second == "A")
names.erase(it++);
else
++it;
In C++11, the use of auto will make this look even better.

Find nearest points in a vector

Given a sorted vector with a number of values, as in the following example:
std::vector<double> f;
f.pushback(10);
f.pushback(100);
f.pushback(1000);
f.pushback(10000);
I'm looking for the most elegant way to retrieve for any double d the two values that are immediately adjacent to it. For example, given the value "45", I'd like this to return "10" and "100".
I was looking at lower_bound and upper_bound, but they don't do what I want. Can you help?
EDIT: I've decided to post my own anser, as it is somewhat a composite of all the helpful answers that I got in this thread. I've voted up those answers which I thought were most helpful.
Thanks everyone,
Dave
You can grab both values (if they exist) in one call with equal_range(). It returns a std::pair of iterators, with first being the first location and second being the last location in which you could insert the value passed without violating ordering. To strictly meet your criteria, you'd have to decrement the iterator in first, after verifying that it wasn't equal to the vector's begin().
You can use STL's lower_bound to get want you want in a few lines of code. lower_bound uses binary search under the hood, so your runtime is O(log n).
double val = 45;
double lower, upper;
std::vector<double>::iterator it;
it = lower_bound(f.begin(), f.end(), val);
if (it == f.begin()) upper = *it; // no smaller value than val in vector
else if (it == f.end()) lower = *(it-1); // no bigger value than val in vector
else {
lower = *(it-1);
upper = *it;
}
You could simply use a binary search, which will run in O(log(n)).
Here is a Lua snippet (I don't have time to do it in C++, sorry) which does what you want, except for limit conditions (that you did not define anyway) :
function search(value, list, first, last)
if not first then first = 1; last = #list end
if last - first < 2 then
return list[first], list[last]
end
local median = math.ceil(first + (last - first)/2)
if list[median] > value then
return search(value, list, first, median)
else
return search(value, list, median, last)
end
end
local list = {1,10,100,1000}
print(search(arg[1] + 0, list))
It takes the value to search from the command line :
$ lua search.lua 10 # didn't know what to do in this case
10 100
$ lua search.lua 101
100 1000
$ lua search.lua 99
10 100
I'm going to post my own anser, and vote anyone up that helped me to reach it, since this is what I'll use in the end, and you've all helped me reach this conclusion. Comments are welcome.
std::pair<value_type, value_type> GetDivisions(const value_type& from) const
{
if (m_divisions.empty())
throw 0; // Can't help you if we're empty.
std::vector<value_type>::const_iterator it =
std::lower_bound(m_divisions.begin(), m_divisions.end(), from);
if (it == m_divisions.end())
return std::make_pair(m_divisions.back(), m_divisions.back());
else if (it == m_divisions.begin())
return std::make_pair(m_divisions.front(), m_divisions.front());
else
return std::make_pair(*(it - 1), *(it));
}
What if (in your case) d is less than the first element or more than the last? And how to deal with negative values? By the way: guaranteeing that your "d" lives between the first and the last value of your vector you can do like that:
// Your initializations
std::vector<double>::const_iterator sit = f.begin();
double upper, lower;
Here is the rest:
while ( *sit < d ) // if the element is still less than your d
++sit; // increase your iterator
upper = *sit; // here you get the upper value
lower = *(--sit); // and here your lower
Elegant enough? :/
You could do a search in your vector for your value (which would tell you where your value would be if it were in the vector) and then return the value before and after that location. So searching for 45 would tell you it should be at index=1 and then you would return 0 and 1 (depending on your implementation of the search, you'll either get the index of the smaller value or the index of the larger value, but this is easy to check with a couple boundary conditions). This should be able to run in O(log n) where n is the number of elements in your vector.
I would write something like this, didn't test if this compiles, but you get the idea:
template <typename Iterator>
std::pair<Iterator, Iterator> find_best_pair(Iterator first, Iterator last, const typename Iterator::value_type & val)
{
std::pair<Iterator, Iterator> result(last, last);
typename Iterator::difference_type size = std::distance(first, last);
if (size == 2)
{
// if the container is of size 2, the answer is the two elements
result.first = first;
result.first = first;
++result.first;
}
else
{
// must be of at lease size 3
if (size > 2)
{
Iterator second = first;
++second;
Iterator prev_last = last;
--prev_last;
Iterator it(std::lower_bound(second, last, val));
if (it != last)
{
result.first = it;
result.second = it;
if (it != prev_last)
{
// if this is not the previous last
// then the answer is (it, it + 1)
++result.second;
}
else
{
// if this the previous last
// then the answer is (it - 1, it)
--result.first;
}
}
}
}
return result;
}
I wrote up this little function, which seems to fit the more general case you wanted. I haven't tested it totally, but I did write a little test code (included).
#include <algorithm>
#include <iostream>
#include <vector>
template <class RandomAccessIt, class Container, class T>
std::pair<RandomAccessIt, RandomAccessIt> bracket_range(RandomAccessIt begin, RandomAccessIt end, Container& c, T val)
{
typename Container::iterator first;
typename Container::iterator second;
first = std::find(begin, end, val);
//Find the first value after this by iteration
second = first;
if (first == begin){ // Found the first element, so set this to end to indicate no lower values
first = end;
}
else if (first != end && first != begin) --first; //Set this to the first value before the found one, if the value was found
while (second != end && *second == val) ++second;
return std::make_pair(first,second);
}
int main(int argc, _TCHAR* argv[])
{
std::vector<int> values;
std::pair<std::vector<int>::iterator, std::vector<int>::iterator> vals;
for (int i = 1; i < 9; ++i) values.push_back(i);
for (int i = 0; i < 10; ++i){
vals = bracket_range(values.begin(), values.end(),values, i);
if (vals.first == values.end() && vals.second == values.end()){ // Not found at all
std::cout << i << " is not in the container." << std::endl;
}
else if (vals.first == values.end()){ // No value lower
std::cout << i << ": " << "None Lower," << *(vals.second) << std::endl;
}
else if (vals.second == values.end()) { // No value higher
std::cout << i << ": " << *(vals.first) << ", None Higher" << std::endl;
}
else{
std::cout << i << ": " << *(vals.first) << "," << *(vals.second) << std::endl;
}
}
return 0;
}
Based on the code that tunnuz posted, here you have some improvements regarding bound checking:
template<typename T>
void find_enclosing_values(const std::vector<T> &vec, const T &value, T &lower, T &upper, const T &invalid_value)
{
std::vector<T>::const_iterator it = vec.begin();
while (it != vec.end() && *it < value)
++it;
if(it != vec.end())
upper = *it;
else
upper = invalid_value;
if(it == vec.begin())
lower = invalid_value;
else
lower = *(--it);
}
Example of usage:
std::vector<int> v;
v.push_back(3);
v.push_back(7);
v.push_back(10);
int lower, upper;
find_enclosing_values(v, 4, lower, upper, -1);
std::cout<<"lower "<<lower<<" upper "<<upper<<std::endl;
If you have the ability to use some other data structure (not a vector), I'd suggest a B-tree. If you data is unchanging, I believe you can retrieve the result in constant time (logarithmic time at the worst).