Delete an element from a list C++ - c++

I have a problem, I'm trying to delete an element in a string list but it doesn't work for the last position. I would also like to display the position of the iterator with an arithmetic operation.
list l = {"a","b","c", "d"};
for(std::list<string>::iterator it = l.begin(); it != l.end(); it++)
cout << " &l["<< it - l.begin() <<"]: " << &*it << " l["<< it - l.begin() <<"]: " << *it << endl;
cout << endl;
for(std::list<string>::iterator itt = l.begin(); itt != l.end(); itt++){
if(*itt == "d") itt = l.erase(itt);
cout << " &l["<< itt - l.begin() <<"]: " << &*itt << " l["<< itt - l.begin() <<"]: " << *itt << endl;
}
Thank you for your help.

It "doesn't work" because this line will cause itt to become the end() iterator when erasing the last element:
if(*itt == "d") itt = l.erase(itt);
Then the for loop does itt++ before the loop condition check, and incrementing the end() iterator is undefined behavior.
You need to modify your loop like this:
for (std::list<string>::iterator itt = l.begin(); itt != l.end(); /* */) {
if (*itt == "d") {
itt = l.erase(itt);
} else {
++itt;
}
// You cannot safely access *itt here because it might be l.end()
}

Two issues. First:
it - l.begin()
List iterators aren't random access, so they don't have operator-() defined for the obvious reason that that would be an expensive operation. If you want to do that, you have to do:
std::distance(l.begin(), it);
Second, the line:
itt = l.erase(itt);
for the last element will cause itt to become l.end(), so the subsequent itt++ is undefined behavior. What you will have to do instead is conditionally increment the iterator:
for (std::list<string>::iterator itt = l.begin(); itt != l.end(); /* nothing */) {
if (*itt == "d") {
itt = l.erase(itt);
}
else {
// cout stuff here
++itt;
}
}

Related

How to repeat and print 2 or more for loops?

I am trying to print out values from my txt file. I created a struct so that I can easily search for the element in the txt file. So for my first for loop I searched for "CC" as the first option and then I print. It works. However when I try copy the same loop and search for something else, lets say "SN" so that I can print all the values with SN as the first option, the second and subsequent loop does not print. It only works if I copy the long code again and create a new function but I do not want to do that because I try to keep it compact.
cout << "\nCC Students:" << endl;
int cc = 0;
for (; it != v.end(); it++)
{
if ((*it).First == "CC"){
cout << (*it).Name << " " << (*it).GPA << "\n";
if (++cc == 10)
break;
}
} // can print
cout << "\nSN Students:" << endl;
int sn = 0;
for (; it != v.end(); it++)
{
if ((*it).First == "SN"){
cout << (*it).Name << " " << (*it).GPA << "\n";
if (++sn == 10)
break;
}
} // cannot print
The question doesn't show the initialization of it, but from the context it seems to be an iterator on v. The first loop exhausts the iterator, and terminates when it reaches v.end(). When you start another loop, you should reinitialize it to v.begin(), e.g.:
for (it = v.begin(); it != v.end(); it++)
// Here ^

Error while simultaneously accessing members of two lists?

I am facing some unknown errors while iterating through two lists simultaneously in c++ (visual studio). Two lists are of the same length.
I am following the procedure, mentioned in (link). Unable to figure out where am I making mistake. Could anybody help me resolve this error
Function with for loop
int Two_Lists_ForLoop(std::initializer_list<dmat> list1, std::initializer_list<string> list2)
{
std::list<dmat>::iterator it1 = list1.begin();
std::list<string>::iterator it2 = list2.begin();
for (; it1 != list1.end() && it2 != list2.end(); ++it1, ++it2){
//run some code
cout << *it1 << endl;
cout << *it2 << endl;
}
return 0;
}
Function with while loop
int Two_Lists_WhileLoop(std::initializer_list<dvec> list1, std::initializer_list<string> list2)
{
std::list<dvec>::iterator it1 = list1.begin();
std::list<string>::iterator it2 = list2.begin();
while (it1 != list1.end() && it2 != list2.end()) {
//run some code
cout << *it1 << endl;
cout << *it2 << endl;
it1++;
it2++;
}
return 0;
}
I've included list.h headerfile. The errors I am getting are as follows (I do not know, how to resolve these errors)
Thanks in advance.

C++ Iterator access next element for comparison

I'm trying to compare two elements in a List by 'peeking' into the next element in the list. Using C++11.
Is this possible? I'm having some trouble.
#include <list>
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
list<int> intList;
intList.push_back(10);
intList.push_back(20);
intList.push_back(30);
intList.push_back(30);
list<int>::iterator it;
for (it = intList.begin(); it != intList.end(); it++)
{
if (*it == *it + 1)
cout << "Duplicate: " << *it << '\n';
}
}
Yes, it's possible:
assert(!intList.empty()); // else ++begin is UB
for (list<int>::iterator it1 = intList.begin(), it2 = ++intList.begin();
it2 != intList.end(); ++it1, ++it2)
{
if (*it1 == *it2)
cout << "Duplicate: " << *it1 << '\n';
}
Your search can be simplified by using std::adjacent_find() instead (which supports std::list iterators):
Searches the range [first, last) for two consecutive identical elements.
For example:
list<int>::iterator it = std::adjacent_find(intList.begin(), intList.end());
if (it != intList.end())
cout << "Duplicate: " << *it << '\n';`
It's possible but your confronting *it with *it augmented by 1 (that is even different).
I suppose your intention was to confront two adiacent element of the list, so [thanks to DeiDei for the correction]
if ( false == intList.empty() )
{
auto it { intList.cbegin() };
auto oldVal { *it };
for ( ; ++it != intList.cend() ; oldVal = *it )
{
if ( *it == oldVal )
cout << "Duplicate: " << oldVal << '\n';
}
}
p.s.: sorry for my bad English

Checking if current element is last element of set

I am trying to write a print function for set in C++, and this is what I wrote :
void print_set(set<int> &s)
{
cout<<"{";
for(auto it = s.begin() ; it!=s.end() ; ++it)
{
cout<<*it;
if(it!=(s.end()-1)) //shows error here
cout<<",";
}
cout<<"}";
}
But I am getting error. How can I check whether current element is last element or not ?
set's integers are not random-access, so you can't do arithmetic on them. Use std::prev instead.
May I suggest an alternative approach?
Print the comma before each element, except the first:
void print_set(set<int> &s)
{
cout << "{";
for(auto it = s.begin() ; it != s.end() ; ++it)
{
if(it != s.begin())
cout << ", ";
cout << *it;
}
cout << "}";
}
Simply check whether the next element equals the end:
auto next = it;
++next;
if (next != s.end())
cout << ",";
You can only apply the ++ and -- operators on set iterators. Adding a number is not defined. You can make your code work like so:
void print_set(set<int> &s)
{
cout<<"{";
auto second_to_last = s.end();
if (!s.empty()) {
second_to_last--;
}
for(auto it = s.begin() ; it!=s.end() ; ++it)
{
cout<<*it;
if(it!=second_to_last) {
cout<<", ";
}
}
cout<<"}";
}
What this code does is essentially store an iterator to the second to last element once and then compare the element you have with it. Please note that second_to_last will not be accurate if the set is empty but the code will still work as expected.
What I do in this case:
void print_set(const std::set<int>& s)
{
const char* sep = "";
std::cout << "{";
for (int e : s)
{
std::cout << sep << e;
sep = ", ";
}
std::cout << "}";
}

forloop, iterators and vectors doesn't cooperate with me

Why does this work fine for me:
for(int i = 0; i < vec.size(); i++)
{
os << vec[i] << " ";
}
while this doesn't:
for(vector<int>::iterator it = vec.begin(); it < vec.end(); it++)
{
os << vec[*it] << " ";
}
You should be printing *it instead of using it as the index and you should probably change the condition to it != vec.end().
You're using the iterator wrong, it should be:
for(vector<int>::iterator it = vec.begin(); it < vec.end(); it++)
{
os << *it << " ";
}
Your code just attempts to print the element at index *it, which might not even be valid.