Search code examples
c++classerror-handlingconstants

How to use 'mutable' correctly so the set iterator won't be const?


I'm trying to remove the employee in my code and change his salary back to 0, but all I get in the function is his id. I used the built in iterator for the set, but found out that it is const. How can I use mutable, or some other way to change his salary to 0? I have an employee and a manager- the manager can hire or fire the employee, which will change his salary (obviously). This is my code:

class Manager : public Citizen {
    protected:
        int salary;
        std::set<Employee> employees;

void removeEmployee(const int id) {
            mutable std::set<Employee>::iterator employee;

            for (employee = this->employees.begin(); employee != this->employees.end(); employee++) {
                if (employee->getId() == id) {
                    employee->setSalary(0);
                    this->employees.erase(employee);
                    return;
                }
            }
            throw EmployeeNotHired();
        }

And the error I'm getting-

C:\Users\User\CLionProjects\hw2Cpp\Manager.h:53:50: error: non-member 'employee' cannot be declared 'mutable'
             mutable std::set<Employee>::iterator employee;
                                                  ^~~~~~~~
C:\Users\User\CLionProjects\hw2Cpp\Manager.h:57:42: error: passing 'const mtm::Employee' as 'this' argument discards qualifiers [-fpermissive]
                     employee->setSalary(0);

What should I do?

**** edit**** I tried changing it to:

class Employee : public Citizen {
protected:
    mutable int salary;
    mutable int score;
    std::set<Skill> skills;

But I am still unable to change the salary to 0.

error: passing 'const mtm::Employee' as 'this' argument discards qualifiers [-fpermissive]
                     employee->setSalary(0);

Solution

  • The design of std::set ensures that elements of the set "cannot be modified" i.e. they can only be accessed via const references. This is for a good reason: std::set relies on the order of its elements remaining the same thoughout the lifetime to maintain its internal search tree datastructure.

    Ways to deal with this are:

    1. declaring setSalary as a const member function. (Not a good idea since setting the salary probably does modify the object in a way that wouldn't be expected of a const function.)
    2. Extract the employee (C++17)
      //employee->setSalary(0);
      //this->employees.erase(employee);
      auto node = employees.extract(employee);
      node.value().setSalary(0);
      
    3. Choose a different data structure such as a std::unordered_map<int, Employee> mapping from id to Employee or std::vector<Employee>.

    However unless the setSalary function has effects other than modifying the Employee object, just remove the object from the set; The object is deleted in the process anyways...