Remove object from list based on object property - c++

my code is:
class Room {
public:
int id;
string name;
int ownerFd;
Room(int id, string name, int ownerFd)
{
this->id = id;
this->name = name;
this->ownerFd = ownerFd;
}
};
void RemoveUserRooms(int ownerFd) {
for(auto& room : rooms) {
if (room.ownerFd == ownerFd) {
//remove room from list
}
}
}
What I want to do is to remove object from list. I already tried with remove and erase but that seems not to work in this way. Is is possible to do with list?

Use iterator and erase while properly updating the iterator.
for(auto i=rooms.begin();i!=rooms.end();)
{
if((*i).ownerFd == ownerFd)
i=rooms.erase(i);
else
i++;
}
Or better ,
you can use remove_if
rooms.remove_if([ownerFd](Room i){return i.ownerFd == ownerFd;});

Related

How to pass array of object pointers to function?

I am having trouble passing an array of object pointers from main() to a function from different class.
I created an array of object pointers listPin main() and I want to modify the array with a function editProduct in class Manager such as adding new or edit object.
Furthermore, I want to pass the whole listP array instead of listP[index]. How to achieve this or is there any better way? Sorry, I am very new to c++.
#include <iostream>
using namespace std;
class Product
{
protected:
string id, name;
float price;
public:
Product()
{
id = "";
name = "";
price = 0;
}
Product(string _id, string _name, float _price)
{
id = _id;
name = _name;
price = _price;
}
};
class Manager
{
protected:
string id, pass;
public:
Manager(string _id, string _pass)
{
id = _id;
pass = _pass;
}
string getId() const { return id; }
string getPass() const { return pass; }
void editProduct(/*array of listP*/ )
{
//i can edit array of listP here without copying
}
};
int main()
{
int numProduct = 5;
int numManager = 2;
Product* listP[numProduct];
Manager* listM[numManager] = { new Manager("1","alex"), new Manager("2", "Felix") };
bool exist = false;
int index = 0;
for (int i = 0; i < numProduct; i++) { //initialize to default value
listP[i] = new Product();
}
string ID, PASS;
cin >> ID;
cin >> PASS;
for (int i = 0; i < numManager; i++)
{
if (listM[i]->getId() == ID && listM[i]->getPass() == PASS) {
exist = true;
index = i;
}
}
if (exist == true)
listM[index]->editProduct(/*array of listP */);
return 0;
}
Since the listP is a pointer to an array of Product, you have the following two option to pass it to the function.
The editProduct can be changed to accept the pointer to an array of size N, where N is the size of the passed pointer to the array, which is known at compile time:
template<std::size_t N>
void editProduct(Product* (&listP)[N])
{
// Now the listP can be edited, here without copying
}
or it must accept a pointer to an object, so that it can refer the array
void editProduct(Product** listP)
{
// find the array size for iterating through the elements
}
In above both cases, you will call the function as
listM[index]->editProduct(listP);
That been said, your code has a few issues.
First, the array sizes numProduct and numManager must be compiled time constants, so that you don't end up creating a non-standard variable length array.
Memory leak at the end of main as you have not deleted what you have newed.
Also be aware Why is "using namespace std;" considered bad practice?
You could have simply used std::array, or std::vector depending on where the object should be allocated in memory. By which, you would have avoided all these issues of memory leak as well as pointer syntaxes.
For example, using std::vector, you could do simply
#include <vector>
// in Manager class
void editProduct(std::vector<Product>& listP)
{
// listP.size() for size of the array.
// pass by reference and edit the listP!
}
in main()
// 5 Product objects, and initialize to default value
std::vector<Product> listP(5);
std::vector<Manager> listM{ {"1","alex"}, {"2", "Felix"} };
// ... other codes
for (const Manager& mgr : listM)
{
if (mgr.getId() == ID && mgr.getPass() == PASS)
{
// ... code
}
}
if (exist == true) {
listM[index]->editProduct(listP);
}
You cannot have arrays as parameters in C++, you can only have pointers. Since your array is an array of pointers you can use a double pointer to access the array.
void editProduct(Product** listP){
and
listM[index]->editProduct(listP);
Of course none of these arrays of pointers are necessary. You could simplify your code a lot if you just used regular arrays.
Product listP[numProduct];
Manager listM[numManager] = { Manager("1","alex"), Manager("2", "Felix")};
...
for(int i = 0; i < numManager; i++ ){
if(listM[i].getId() == ID && listM[i].getPass() == PASS) {
exist = true;
index = i;
}
}
if(exist == true){
listM[index].editProduct(listP);
}

Cannot erase a shared_ptr from set

I am trying to have an object with a set of pointers to another object. when I try to erase on of the set's values I get an error and crash, I really dont know what could be causing it. here is the library and after that the main function:
when I try to run it it does everything its supposed to do, and when it gets to the removeemployee it crashes and sends out the following: Process finished with exit code -1073740940 (0xC0000374)
I run it on clion if that matters, and in c++11.
#include <ostream>
#include <iostream>
#include "Manager.h"
Manager::Manager(int id, string firstName, string lastName, int birthYear)
: Citizen(id, firstName, lastName,birthYear), salary(0), employees(), work_flag(false) {}
int Manager::getSalary() const {
return salary;
}
void Manager::setSalary(int _salary) {
if((salary + _salary) < 0){
salary = 0;
}else {
salary += _salary;
}
}
void Manager::addEmployee(Employee* employee_add) {
shared_ptr<Employee> employee(employee_add);
if(employees.find(employee) != employees.end()){
throw mtm::EmployeeAlreadyExists();
}
employees.emplace(employee);
}
//this is the function
void Manager::removeEmployee(int id) {
for(auto it = employees.begin(); it != employees.end(); it++){
if(it->get()->getId() == id){
employees.erase(it);
return;
}
}
throw mtm::EmployeeDoesNotExists();
}
Manager *Manager::clone() {
return new Manager(*this);
}
ostream &Manager::printShort(ostream &os) const {
os<<this->getFirstName()<<" "<<this->getLastName()<<endl;
os<<"Salary :"<<this->getSalary()<<endl;
return os;
}
ostream &Manager::printLong(ostream &os) const {
os<<this->getFirstName()<<" "<<this->getLastName()<<endl;
os<<"id - "<<this->getId()<<" birth_year - "<<this->getBirthYear()<<endl;
os<<"Salary :"<<this->getSalary()<<endl;
os<<"Employees:"<<endl;
for(const auto & employee : employees){
employee->printShort(os);
}
return os;
}
bool Manager::findEmployee(int id) {
int i = 0;
for(const auto & employee : employees){
cout<<++i<<endl;
if(employee->getId() == id){
cout<<"return true"<<endl;
return true;
}
}
cout<<"return false"<<endl;
return false;
}
bool Manager::isWorkFlag() const {
return work_flag;
}
void Manager::setWorkFlag(bool workFlag) {
work_flag = workFlag;
}
and this is the main function:
int main() {
Employee e1(1, "John", "Williams", 2002);
Employee e2(2, "Alex", "Martinez", 2000);
Manager m1(1,"Robert", "stark", 1980);
m1.addEmployee(&e1);
m1.addEmployee(&e2);
Employee e3(7, "Reuven", "Guetta", 2001);
m1.addEmployee(&e3);
m1.printLong(cout);
cout<<"Delete"<<endl;
//here is the problem
m1.removeEmployee(e2.getId());
m1.printLong(cout);
return 0;
}
shared_ptr<Employee> employee(employee_add);
There is only one reason to have a shared_ptr, in the first place; there's only one reason for its existence; it has only one mission in its life, as explained in every C++ textbook: to be able to new an object, and have the shared_ptr automatically take care of deleteing it when all references to the object are gone, avoiding a memory leak.
In your program this object was not instantiated in dynamic scope with new:
Employee e2(2, "Alex", "Martinez", 2000);
Manager m1(1,"Robert", "stark", 1980);
m1.addEmployee(&e1);
// etc, etc, etc...
and that's the reason for the crash.
If you are not using new, simply get rid of all shared_ptrs in the shown code.

LinkedList sorting a-z

Requirements for this function: If the full name (both the first and last name) is not equal to any full name currently in the list then add it and return true. Elements should be added according to their last name. Elements with the same last name should be added according to
their first names. Otherwise, make no change to the list and return false (indicating that the name is already in the list).
//this function add nodes to the list
//return true if fullname isn't in the list. Else return false if fullname is in the list.
//should be added according to last name.
bool OnlineDating::makeMatch(const std::string& firstName, const std::string& lastName, const OnlineType& value)
{
Node* p = head;
//are these nodes already set to firstName and lastName in this function
Node first;
Node last;
Node* temp = nullptr;
//if the list is empty just insert the fullname and value to the list
if (p == nullptr) {
//add values to the empty list
insertToRear(firstName, lastName, value);
return true;
}
else {
// so this loop is to check if fullname is in the list but first sort in alphebetial order
//sure its added in alphebetical order
//traverse the list after knowing where head is
while (p != nullptr) {
//checking to make sure theres at least another node in the list
if (p->next != nullptr) {
//its not going through ig loop?
//these are used to check and alphebetically selected names
if (p->last > p->next->last) {
insertToRear(p->first, p->last, p->value);
p->next = temp;
return true;
}
else if (p->next->last > p->last) {
insertToRear(p->first, p->last, p->value);
p->next = temp;
return true;
}
//check if full name is already in the list
if (p->last == p->next->last) {
insertToRear(p->first, p->last, p->value);
p->next = temp;
return true;
}
else if (p->first > p->next->first) {
insertToRear(p->first, p->last, p->value);
p->next = temp;
return true;
}
else {
//returns false if it passes through these checks
return false;
}
}
p = p->next;
}
}
}
Here is my main.cpp
int main()
{
OnlineDating clippersGonnaClip;
clippersGonnaClip.makeMatch("Kawhi", "Leonard", 2);
clippersGonnaClip.makeMatch("Paul", "George", 13);
clippersGonnaClip.makeMatch("Ivica", "Zubac", 40);
clippersGonnaClip.makeMatch("Reggie", "Jackson", 1);
clippersGonnaClip.makeMatch("Patrick", "Beverley", 21);
for (int n = 0; n < clippersGonnaClip.howManyMatches(); n++) {
string first;
string last;
int val;
clippersGonnaClip.confirmMatch(n, first, last, val);
cout << first << " " << last << " " << val << endl;
}
return 0;
}
honestly, I just want to create a ptr that will point to each node. Check as long as that node isn't pointing to nullptr, and sort the LinkedList in alphabetical order. finally link the nodes together using my *temp. Why won't it let me go through the if statements every time I compile I get a negative number? Every other function works for this program except this makeMatch(...).
Nothing in the requirements says anything about the data types you need to use. In this case using std::set makes most sense.
By providing a comparison operation on persons and a set you can guarantee uniqueness. Like this :
#include <set>
#include <string>
struct person_t
{
std::string name;
std::string last_name;
unsigned int age;
};
bool operator<(const person_t& lhs, const person_t& rhs)
{
if (lhs.last_name == rhs.last_name)
return lhs.name < rhs.name;
return lhs.last_name < rhs.last_name;
}
int main()
{
// set will ensure all persons are unique
std::set<person_t> persons;
persons.insert({ "Kawhi", "Leonard", 2 });
persons.insert({ "Paul", "George", 13 });
persons.insert({ "Ivica", "Zubac", 40 });
persons.insert({ "Reggie", "Jackson", 1 });
persons.insert({ "Patrick", "Beverley", 21 });
}

how to remove a shared ptr element from set?

I have a set where each element in the set is of type shared_ptr, I want to remove an element from the set, in eclipse the element was actually removed but when I test this in bash with valgrind I get a lot of invalid size mistakes ...
So this made me think that maybe there is a different way to remove element of type shared_ptr ?
Every element in the peoplePointer is a class of certain person:
typedef std::shared_ptr<person> peoplePointer;
class AA {
std::set<peoplePointer> setOfPeople;
public:
// function getName() return name of the person (person is another class)
void removeSomeonefromA(const std::string& name) {
for (std::set<peoplePointer>::iterator it = setOfPeople.begin();it != setOfPeople.end(); it++) {
if(name == (*it).get()->getName()) {
setOfPeople.erase((it));
}
}
}
};
Idea inspired by remove_if equivalent for std::map.
If you are able to use a C++11 or later compiler, you can use:
void removeSomeonefromA(const string& name)
{
for (set<peoplePointer>::iterator it = setOfPeople.begin(); it != setOfPeople.end(); /* Empty */ )
{
if(name == (*it).get()->getName())
{
it = setOfPeople.erase(it);
}
else
{
++it;
}
}
}
If you are required to use a prior compiler version, you can use:
void removeSomeonefromA(const string& name)
{
for (set<peoplePointer>::iterator it = setOfPeople.begin(); it != setOfPeople.end(); /* Empty */ )
{
if(name == (*it).get()->getName())
{
setOfPeople.erase(it++);
}
else
{
++it;
}
}
}

Finding an object in a std list and adding it to another list

I'm trying to create a bookshop management system that will allow me to add previously created authors to a database, create books and then assign an author to a book from the database (which is a std::list). The FindAdd function is supposed to iterate over a list of authors in the database and find a given object (temporary author) in it and then add this object to a book's authors list.
I'm trying to cast the iterator to an object so I'm able to add the author, but this line won't allow me to compile this program (no matching function to call for to Book::AddAuthor(Author*)). I tried it without casting, but of course it won't work. How can I fix this? Or maybe there's an easier method to accomplish what I'm trying to do here?
class Author
{
private:
string name, lname;
public:
bool operator==(const Author & a) const
{
bool test=false;
if(!(this->name.compare(a.name) && this->lname.compare(a.lname)))
test=true;
return test;
}
Author(string namex, string lnamex)
{
name=namex;
lname = lnamex;
}
};
class Book
{
public:
list <Author> Authorzy;
string tytul;
void AddAuthor(Author & x)
{
Authorzy.push_back(x);
}
Book(string tytulx)
{
tytul = tytulx;
}
};
class Database
{
protected:
list <Author> authors;
public:
void AddAuthor(Author x)
{
authors.push_back(x);
}
list <Author> getAuthors
{
return authors;
}
};
void FindAdd(Author & x, Book &y, Database & db)
{
list <Author>:: iterator xx;
xx = find(db.getAuthors().begin(), db.getAuthors().end(), x);
if (xx != db.getAuthors().end())
y.AddAuthor(&*xx);
else cout << "Author not found";
}
int main(){
Author testauthor("test", "test");
Database testdb;
testdb.AddAuthor(testauthor);
Book testbook("Mainbook");
FindAdd(Author notfound("Another", "Guy"), testbook, testdb);
FindAdd(testauthor, testbook, testdb);
}
AddAuthor Just takes a Book Reference, so you dont need to do anything fancy:
if (xx != db.getAuthors().end()) {
y.AddAuthor(*xx); // Just dereference the iterator and pass it
// in, c++ takes care of the rest
} else {
cout << "Author not found";
}