2012-01-16 3 views
4

다음 코드를 갖는C++ : STL : 설정 : 저장된 값을 const와

#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; 
} 

내가 가진이 코드를 컴파일 할 수 없습니다를 (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 

이 컴파일하는 데 도움이 :

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

질문 : 나는 mapmultimap이 값을으로 저장한다는 것을 알고 있습니다.여기서 K는 키이고 V는 값입니다. 우리는 K 객체를 변경할 수 없습니다. 그러나 set<T>multiset<T>은 이 아닌 T으로 개체를 저장합니다. 그래서 나는 왜이 성모가 필요합니까 ??

+4

사실, 나는'set' * 값을 쉽게 수정할 수 없도록 ('const'로) 저장한다고 생각합니다. 값을 수정하면 항목이 세트의 잘못된 위치에있을 가능성이 있으므로 항목 수정을 허용하지 않습니다. –

+2

'std :: unary_function'은 2011 년에 더 이상 사용되지 않으므로 어쨌든 펑터를 람다로 바꾸는 것이 좋습니다. – pmr

+0

이것은'set'을 잘못된 방법으로 사용하고 있다는 경고입니다. 레코드에는 키와 값이 있지만'map' 대신'set'에 저장합니다. – Omnifarious

답변

12

C++ 11 세트 (및 다중 세트)에서 iterator은 물론 const_iterator이 상수 반복기임을 지정합니다. 즉, 키를 수정하는 데 사용할 수 없습니다. 이것들은 키의 변경으로 인해 집합의 불변성이 깨질 위험이 있기 때문입니다. (23.2.4/6 참조)

const_cast은 정의되지 않은 동작에 대한 문을 엽니 다.

+0

+1 참조 : –

+0

위대한 답변. 매우 도움이되어야한다. – DaddyM

+0

나는 ISO/IEC 14882 : 2011 (E) 표준을 가지고있다. 그러나 23.2.4/6은 iterator 타입을 지적하고 있지 않다. 대신에 ** _X :: iterator - 값 유형이 T ** (23.2.4) 인 반복자 유형 – DaddyM

2

C++에서는 연결된 STL 컨테이너의 키를 수정할 수 없으므로 STL 컨테이너의 키를 수정할 수 없습니다. 키를 변경하려면 (1) 기존 키를 찾고 (2) 삭제하고 (3) 새 키를 삽입해야합니다.

지나치게 매력적이지는 않지만, STL에서 연관 컨테이너가 작동하는 방식입니다.

+0

답변 해 주셔서 감사합니다. 매우 도움이 될 것입니다. 덕분에 – DaddyM

4

set의 값은 수정하지 않아야합니다. 예를 들어, 사원 ID를 수정 한 경우 ID가 세트의 잘못된 위치에 있고 세트가 손상 될 수 있습니다.

직원의 필드가 세 개인 경우 집합에 operator<의 _id 필드가 사용됩니다.

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

}; 

따라서, 당신은 아마 다음 이름과 제목을 수정할 수있을 것입니다, 대신 세트의 map<int,Employee>를 사용해야합니다. 나는 또한 직원의 _id 필드를 const int _id으로 만들 것입니다.

은 (그건 그렇고, _로 시작하는 식별자는 기술적으로 예약하고 피해야한다. 그것은 나에게 어떤 문제를 일으킬 결코하지만 지금은 변수 이름의 끝 부분에 밑줄을 넣어 것을 선호합니다.)

+1

. 몇 가지 유용한 점! – DaddyM

0

당신이 할 수있는 간접 표시로 const을 사용하십시오.

그러나 주어진 정렬 된 컨테이너에서 요소의 순서를 변경하지 않도록주의하십시오.