Hello! I'm working on an assignment that requires me to store custom classes in an STL vector and do things like search, display, and delete them, then write them all to file.

This is going well, but my code to delete an object (adapted from this thread) works on any object EXCEPT the last object; it crashes whenever I try to delete the last one in the chain.

Here is my code for the deletion:

vector<course> cache; //holds objects in memory
vector<course>::iterator point; //points at the vector


//fill vector with data, etc etc


cout << "Input course number to delete: ";
cin >> target;
point = cache.begin();

for(int n=0; point != cache.end(); point++, n++) {
   if(point->get_number() == target)
      { cache.erase(point); } //erases object
}

Any idea what I'm doing wrong? Thanks!

Recommended Answers

All 12 Replies

Eh, a general rule of thumb is not to loop with iterators if you're going to modify the container. The good news is that the algorithm header has a function template that you can use to remove all occurrences of an item:

#include <algorithm>

cout << "Input course number to delete: ";
cin >> target;

cache.erase ( remove ( cache.begin(), cache.end(), target ), cache.end() );

However, my course class is composed as follows:

class course {
   private:
      string prefix;
      int number;
      string title;
      int credits;
      char grade;
   public:
      //Constructors
      course();
      course(string, int, string, int, char);
      //Accessors
      void set();
      void print() const;
      string get_prefix() const;
      int get_number() const;
      string get_title() const;
      int get_credits() const;
      char get_grade() const; 
      //Operators
      bool operator < (course) const;
      bool operator > (course) const;
      bool operator == (course) const;
      bool operator != (course) const;
};

Wouldn't that code erase an object any time it found target in the course number or credits, since both are ints?

(sorry for the dumb questions XD)

Also, I got a ton of errors when I slap-dashed that into my code.
(and yes, I have included the algorithm library)

Sorry, I didn't notice you were using custom objects. The easiest solution would be to do some research on remove_if. That function allows you to pass a predicate for custom comparisons. It would probably be easier than modifying your class to remove those errors.

struct eq_course_number
{
  explicit eq_course_number( int n ) : course_num(n) {}
  bool operator() ( const course& c ) const
  { return c.get_number() == course_num ; }
  int course_num ;
};

//
cin >> target;
if( remove_if ( cache.begin(), cache.end(),
                      eq_course_number(target) ) != cache.end() )
      cache.pop_back() ;

an alternative is to overload operator== to test for equivalence between course and an integer course_number. then remove could be used (as in Narue's post)

if( remove_if ( cache.begin(), cache.end(),
                      eq_course_number(target) ) != cache.end() )
      cache.pop_back() ;

this will remove only one object; i'd assumed that courses in the cache would be unique. if you want to remove many elements which have the same course number, it needs to be written as Narue had suggested.

cache.erase( remove_if ( cache.begin(), cache.end(),
                      eq_course_number(target) ), cache.end() ) ;

this would also work if there is just one element or even none at all.

The object (to hold college course data) would probably only contain one object of a given course number, since it would be unlikely to be enrolled in two identical college courses in the same semester.

Could someone explain to me how the

explicit eq_course_number( int n ) : course_num(n) {}

works? I'm farmiliar with using class objects and the () operator to get stuff done, but I'm having trouble passing extra parameters to functions like he does.

EDIT: And, I thought pop_back() will always remove the LAST element in a vector.
The code still works, I'm just a tad confused on how it does so :)

Note: I also threw in an overloaded == operator for use with integers

bool course::operator == (int n) const //returns based on class #
{//overloaded for use with an integer
   if (number == n) {
      return true;
   } else {
      return false;
   }
}

And now Narue's method works!

Could someone explain to me how the

explicit eq_course_number( int n ) : course_num(n) {}

works?

eq_course_number is a class and the line you are referring to is the constructor. logically, the == operation is a binary one; the remove_if requires a unary predicate. so we have an object which stores the extra information in a member variable and uses it as the second parameter when the function ( operator() ) is called with just one parameter. in c++ jargon, this is called binding an argument.

the explicit keyword disables an implicit conversion from an int to an object of type eq_course_number. it does not affect anything else.

EDIT: And, I thought pop_back() will always remove the LAST element in a vector.
The code still works, I'm just a tad confused on how it does so :)

remove or remove_if does not really remove an element (in the sense that erase or pop_back does), it rearranges the sequence so that the elements which satisfy the condition are towards the end of the sequence; those which do not are towards the beginning. and their relative position is undisturbed. and it returns an iterator to the first element that satisfies the condition.
i assumed that there would be at most one such element; so a pop_back would erase it. narue assumed that there could be more than one; so an erase from there upto end would erase all of them.

infact remove does more or less the same thing that the partition algorithm does; in this case partition would have been faster (as the iterator for the vector can be used bidirectionally). i went along with the remove_if because it had already been mentioned, thought it might be less confusing!

Hmmmm. The explicit keyword and the different syntax totally made me miss the fact that the line was a constructor ;)

I was having trouble throwing extra parameters at the STL functions, so I had been using... erm... a global variable... That syntax helped me a ton!


Thanks for the help, everyone! Now I just have to get File I/O working....

I was having trouble throwing extra parameters at the STL functions, so I had been using... erm... a global variable... That syntax helped me a ton!

when you get the time, check out the header <functional>. it has a number of function objects and things that operate on function objects (generic binders being one of them).
and if you find that interesting, check out boost::bind and boost::lambda. those should really excite you.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.