C ++: STL: set: stored value constant

Having the following code:

#include <iostream> #include <set> #include <string> #include <functional> using namespace std; class Employee { // ... int _id; string _name; string _title; public: Employee(int id): _id(id) {} string const &name() const { return _name; } void setName(string const &newName) { _name = newName; } string const &title() const { return _title; } void setTitle(string const &newTitle) { _title = newTitle; } int id() const { return _id; } }; struct compEmployeesByID: public binary_function<Employee, Employee, bool> { bool operator()(Employee const &lhs, Employee const &rhs) { return lhs.id() < rhs.id(); } }; int wmain() { Employee emplArr[] = {0, 1, 2, 3, 4}; set<Employee, compEmployeesByID> employees(emplArr, emplArr + sizeof emplArr/sizeof emplArr[0]); // ... set<Employee, compEmployeesByID>::iterator iter = employees.find(2); if (iter != employees.end()) iter->setTitle("Supervisor"); return 0; } 

I can not compile this code with (MSVCPP 11.0):

 1> main.cpp 1>d:\docs\programming\test01\test01\main.cpp(40): error C2662: 'Employee::setTitle' : cannot convert 'this' pointer from 'const Employee' to 'Employee &' 1> Conversion loses qualifiers 

This helps to compile:

  if (iter != employees.end()) const_cast<Employee &>(*iter).setTitle("Supervisor"); 

Question: I know that map and multimap save their values ​​as pair(const K, V) , where K is the key and V is the value. We cannot change the object K. But set<T> and multiset<T> save their object as T , and not as const T So WHY DO I NEED THIS DESIGN?

+4
source share
4 answers

In the C ++ 11 set (and multiset), specify that the iterator as well as const_iterator is a constant iterator, i.e. You cannot use it to change a key. This is due to the fact that any modification of their key risks violates the set of invariants. (See 23.2.4 / 6.)

Your const_cast opens the door to undefined mode.

+12
source

The values ​​in set must not be changed. For example, if you change your employee ID, then he will be in the wrong position in the set, and the set will be broken.

Your employee has three fields, and your set uses the _id field in your operator< .

 class Employee { // ... int _id; string _name; string _title; }; 

Therefore, you should probably use map<int,Employee> instead of your set, then you can change the name and title. I would also make the field _id Employee a const int _id .

(Incidentally, identifiers starting with _ are technically secure and should be avoided. This never causes me any problems, but now I prefer to put an underscore at the end of the variable name.)

+4
source

In C ++, you cannot change the keys of related STL containers because you will break their order. If you want to change the key, you must (1) find the existing key, (2) delete it and (3) insert a new key.

Unfortunately, although this is not very attractive, this is how associative containers work in the STL.

+2
source

You can leave with const only with indirectness.

But be careful not to reorder the elements in this sorted container.

0
source

Source: https://habr.com/ru/post/1391336/


All Articles