2012-01-16 6 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の値がpair(const K, V)ここで、Kはキー、Vは値です。 Kオブジェクトは変更できません。しかし、set<T>multiset<T>は、const Tではなく、オブジェクトをTとして保存します。だから私はなぜこの義経が必要なのですか?

+4

実際、私は '' set''は値を変更できないように(効果的に '' const''として)保存していると思います。値を変更すると、アイテムがセット内の間違った場所にある可能性があるため、アイテムの変更を許可することは意味がありません。 –

+2

'std :: unary_function'は2011年に廃止されましたが、とにかくファンクタをラムダに置き換えることができます。 – pmr

+0

これは間違った方法で 'set'を使っているという警告です。あなたのレコードはキーと値を持っていますが、 'map'ではなく' set'でそれらを保存しています。 – Omnifarious

答えて

12

C++ 11のセット(およびマルチセット)では、iteratorconst_iteratorは定数反復子であると指定します。つまり、キーを変更するために使用することはできません。これは、それらのキーの変更がセットの不変量を破る危険性があるためです。 (23.2.4/6を参照)

const_castは未定義の動作の扉を開きます。

+0

+1のために参考: –

+0

素晴らしい答え。非常に役に立つはずです – DaddyM

+0

私はISO/IEC 14882:2011(E)標準を使っていますが、BUT 23.2.4/6は 'iterator'タイプを指摘していません。代わりに、ここで見ることができます** _ X :: iterator - 値の型がT **(23.2.4)のイテレータ型 – DaddyM

2

C++では、関連付けられているSTLコンテナのキーを変更することはできません。キーを変更する場合は、(1)既存のキーを見つけ、(2)削除し、(3)新しいキーを挿入する必要があります。

これはあまり魅力的ではありませんが、それは連想型コンテナがSTLでどのように機能するかです。

+0

お返事ありがとうございます。非常に役立つはずです。ありがとうございます。 – DaddyM

4

setの値は変更されません。たとえば、従業員のIDを変更した場合、IDはセット内の間違った位置にあり、セットは壊れます。

従業員には3つのフィールドがあり、セットにはoperator<の_idフィールドが使用されています。

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

}; 

したがって、あなたはおそらく、あなたは名前とタイトルを変更することができるだろう、代わりにあなたのセットのmap<int,Employee>を使用する必要があります。また、従業員の_idフィールドをconst int _idにします。

(ちなみに、_で始まる識別子は技術的に予約されており、避けるべきである。それは私にどんな問題を引き起こすことはありませんですが、今、私は、変数名の末尾にアンダースコアを置くことを好む。)

+1

いくつかの有用な点! – DaddyM

0

することができます間接指示だけでconstを取得してください。

ただし、指定したソート済みコンテナ内の要素の順序を変更しないように注意してください。