C ++マップアクセス破棄修飾子(const)


113

次のコードはconstoperator[]メソッドとしてマップを渡すと修飾子が破棄されることを示しています。

#include <iostream>
#include <map>
#include <string>

using namespace std;

class MapWrapper {
public:
    const int &get_value(const int &key) const {
        return _map[key];
    }

private:
    map<int, int> _map;
};

int main() {
    MapWrapper mw;
    cout << mw.get_value(42) << endl;
    return 0;
}

これは、マップアクセスで発生する可能性がある割り当てのためですか?マップアクセスを持つ関数をconstとして宣言することはできませんか?

MapWrapper.cpp:10: error: passing ‘const std::map<int, int, std::less<int>, std::allocator<std::pair<const int, int> > >’ as ‘this’ argument of ‘_Tp& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const _Key&) [with _Key = int, _Tp = int, _Compare = std::less<int>, _Alloc = std::allocator<std::pair<const int, int> >]’ discards qualifiers


ちょっとしたヒントですが、mwはMapWrapper mwとして簡単に宣言できます。
luke

良い点-私はいくつかの言語で書いているので、すべての構文を正規化して、すべてが私の頭の中に収まるようにしています。:)
cdleary 2008年

ありがたいです。ただし、このような場合には、不要なオブジェクトの作成と割り当てが余分にあるので注意してください。
luke

もう1つの良い点-デフォルトの代入演算子に依存することは、公開されている例ではお勧めできません。;)
08年

回答:


152

std::mapさんはoperator []として宣言されていないconst、そしてその行動に起因することができません。

T&operator [](const Key&キー)

keyに対応するキーにマップされている値への参照を返し、そのようなキーがまだ存在しない場合は挿入を実行します。

その結果、関数を宣言できずconst、マップのを使用できませんoperator[]

std::mapfind()関数を使用すると、マップを変更せずにキーを検索できます。

find()リターンiterator、またはconst_iteratorに対してstd::pairキーの両方を含む(.first)と値(.second)。

C ++ 11では、at()forを使用することもできますstd::map。要素が存在しない場合、std::out_of_rangeとは対照的に、関数は例外をスローしますoperator []


8
さらに:VALUE = map.find(KEY)-> second; 'find()'がペアのタイプであるイテレーターを返すことを私は学ばなければなりませんでした。
FlipMcF

5
これをC11で追加すると、std :: map :: at(key)を使用してイテレーターを回避できます。
Juan Besa

3
面白い。私はC ++が左辺値を区別すると思うだろうoperator[](例えばfoo[bar] = baz)と右辺値operator[](例えばx = foo[bar]) -後者は確かにconstの可能性があります。
Claudiu

15

operator[]はconst修飾されたオーバーロードがないため、const修飾された関数で安全に使用できません。これは、現在のオーバーロードが、キー値の返却と設定の両方の目的で構築されたためと考えられます。

代わりに、以下を使用できます。

VALUE = map.find(KEY)->second;

または、C ++ 11では、at()演算子を使用できます。

VALUE = map.at(KEY);

map.find(KEY)->second; マップ値が文字列の場合、安全ではありません。KEYが見つからない場合、ゴミを表示する傾向があります。
サイアム

1
これは、要点を説明した適切に説明された回答です。昨日、同様のケースで何が起こっているのかを理解するために2時間を費やしました。エラーメッセージがせいぜい誤解を招くものであることに同意できますか?'this'という単語がなく、より一般的な修飾子の代わりにconst-nessを参照した場合、私はもっと明確になるでしょう。
カーニカー

11

あなたは使用することはできませんoperator[]で地図上constその方法ではないとしてconst、それはあなたが(あなたがに割り当てることができるマップを変更することを可能にするとして_map[key])。find代わりにメソッドを使用してみてください。


1
説明として:キーが存在しない場合、マップのoperator []はどうすればよいですか?マップが非constの場合、キーはデフォルトで作成された値で追加されます。マップがconstの場合、operator []は何を返すことができますか?そのキーには値がありません。

これは、要点を説明した適切に説明された回答です。昨日、同様のケースで何が起こっているのかを理解するために2時間を費やしました。エラーメッセージがせいぜい誤解を招くものであることに同意できますか?'this'という単語がなく、より一般的な修飾子の代わりにconst-nessを参照した場合、私はもっと明確になるでしょう。
カーニカー

7

GCCヘッダーのいくつかの新しいバージョン(私のマシンでは4.1および4.2)には非標準のメンバー関数map :: at()があり、これはconstと宣言されており、キーがマップにない場合はstd :: out_of_rangeをスローします。

const mapped_type& at(const key_type& __k) const

関数のコメントの参照から、これは標準ライブラリの新しいメンバー関数として提案されているようです。


それはちょっと気まぐれだと思います。at関数は次期標準の一部ですが、現在のat()は見つかりません。
セバスチャンマッハ

'at'はC ++ 11の一部です。
エティエンヌ2014年

0

まず、_で始まるシンボルは、言語の実装/コンパイラの作成者に予約されているため、使用しないでください。_mapが誰かのコンパイラの構文エラーになるのは非常に簡単であり、あなたが責任を負うのは自分だけです。

アンダースコアを使用する場合は、最初ではなく最後に配置します。Microsoftのコードがそれを実行しているのを見たので、おそらくこの間違いを犯しました。覚えておいてください、彼らは彼ら自身のコンパイラーを書いているので、彼らはそれを回避できるかもしれません。それでも、それは悪い考えです。

演算子[]は参照を返すだけでなく、実際にマップにエントリを作成します。したがって、マッピングを取得しているだけではなく、マッピングがない場合は作成しています。それはあなたが意図したものではありません。


5
あなたのポイント_は間違っています。2つの下線(__example)で始まる識別子、または1つの下線と大文字(_Example)で始まる識別子は予約されています。 _example予約されていません。
2013年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.