Classes - Remove a specific object from a vector of objects

Viewed 58

I am working on a personal project and I have a bookshelf class and book class. I am implementing some functions and right now I'm implementing a remove_book function that takes a parameter of the title of the book they want removed from the bookshelf. However I dont know how I would implement that. As an argument you can use any string. You will use the function get_title to compare the used argument with titles of elements in the vector and if such an element exists you can remove it from the vector.

I want to avoid loops as much as possible and use some STL algorithms like remove and then erase. How would this function be implemented in the best way?


#include <iostream>
#include <string>
#include <vector>

using namespace std;

class Bookshelf {
 public:
  Bookshelf() {}
  class Book {
   private:
    string title{};
    string author{};
    int pages{};

   public:
    Book(string const& t, string const& a, int const p)
                    : title{t}, author{a}, pages{p}
    {}

    string get_title() const {
      return title;
    }

    void print() const {
      cout << title << ", " << author << ", " << pages << endl;
    }
           
  };

  void add_book(Book const& b) {
    bookshelf.push_back(b);
  }

  void remove_book(string const& choice, vector<Book>& books) {
           // remove(books.begin(), books.end(), ????)
  }

  void print_bookshelf() const {
    for (const auto& e : bookshelf) {
        e.print();  // this will print out our current vector and if we change
        // it will change,
        // instead of creating a copy which is memory consuming
      }
       
  }
 private:
  vector<Book> bookshelf{};
};

int main() {
  Bookshelf::Book book_1("Hej", "Me", 100);
  Bookshelf::Book book_2("Yo", "Me", 150);
  Bookshelf bookshelf_1;

  book_1.print();

  bookshelf_1.add_book(book_1);
  bookshelf_1.add_book(book_2);
  bookshelf_1.print_bookshelf();

  return 0;
}
1 Answers

The books parameter is worthless. You're trying to remove a book from the bookshelf collection. So do that. Search for the book by linear search evaluating title, and if discovered, remove it from the shelf:

void remove_book(string const &choice)
{
    bookshelf.erase(std::find_if(bookshelf.begin(), bookshelf.end(), 
        [&](Book const& b){ return b.get_title() == choice; }));
}

This will remove at-most one book whose title matches the choice definition.

To remove all books with matching title (perhaps you have six copies of the same book on your shelf), a remove/erase idiom is more appropriate:

void remove_book(string const &choice)
{
    bookshelf.erase(std::remove_if(bookshelf.begin(), bookshelf.end(), 
        [&](Book const& b){ return b.get_title() == choice; }), bookshelf.end());
}

std::remove_if works by moving and shifting all elements in the sequence in such a way that the matching elements appear on the "end" of the sequence, then returns an iterator to the first element of those that were moved there. An example is worth a thousand words. Suppose we had a sequence of integers that looked like this:

1 2 3 2 2 4 5 6 2 3

Now supposed we're trying to remove all instances of the value 2. Using the idiom above, first std::remove_if will xform the sequence into this (with the returned iterator marked by ^):

1 3 4 5 6 3 2 2 2 2
            ^

Then, the sequence erase method is called, using the iterator above, through the end, as the segment to remove. I.e this:

1 3 4 5 6 3 2 2 2 2
            -------

will be erased, leaving you with:

1 3 4 5 6 3

Hopefully that explains how remove/erase works.

Related