[]演算子がSTLマップのconstではないのはなぜですか?


89

質問のために考案された例:

void MyClass::MyFunction( int x ) const
{
  std::cout << m_map[x] << std::endl
}

[]演算子は非定数であるため、これはコンパイルされません。

[]構文は非常にきれいに見えるので、これは残念です。代わりに、私は次のようなことをしなければなりません:

void MyClass::MyFunction( int x ) const
{
  MyMap iter = m_map.find(x);
  std::cout << iter->second << std::endl
}

これはいつも私を悩ませてきました。[]演算子が非定数なのはなぜですか?


5
operator[]指定された要素が存在しない場合、何が生成されますか?
Frerich Raabe 2011

4
@Frerich Raabe:atメンバー関数と同じ:throw std :: out_of_range
Jean-Simon Brochu

回答:


90

Forstd::mapstd::unordered_mapoperator[]は、以前に存在していなかった場合、インデックス値をコンテナに挿入します。少し直感的ではありませんが、そうです。

失敗してデフォルト値を挿入できるようにする必要があるためconst、コンテナーのインスタンスで演算子を使用することはできません。

http://en.cppreference.com/w/cpp/container/map/operator_at


3
std::setはありませんoperator[]
avakar 2009

2
それは正しい答えですが、constバージョンは「at」メンバーと同じことを行うことができます。それはstd :: out_of_rangeをスローします...–
Jean-Simon Brochu

値を読み取るために使用される場合、提供するデフォルト値はありません。std::vectorである読み取り演算子[]がありconstます。map同じことをする必要があります。
wcochran

51

これで、C ++ 11では、at()を使用てよりクリーンなバージョンを作成できます。

void MyClass::MyFunction( int x ) const
{
  std::cout << m_map.at(x) << std::endl;
}

4
mapconstとnon-constがある場合at()、なぜ同じではないのoperator[]ですか?constバージョンでは何も挿入せずにスローしますか?(または、std :: optionalが標準になったときにオプションを返す)
einpoklum 2015

@einpoklum constの正確さのポイントは、ほとんどが静的なコンパイル時のチェックです。constオブジェクトを正しく使用しなかったため、例外をスローするよりもコンパイラーが文句を言うほうがいいです。
Millie Smith

@einpoklum非常に遅いですが、他の読者にとっては、このような異なることを行う2つのオーバーロードがあるとひどいことになります。唯一の理由atは2つのフレーバーがあるためです。これは、を実行するためです。return *this;オーバーロードの唯一の違いは、const返される参照の-nessです。両方atの実際の効果はまったく同じです(つまり、効果はありません)。
HTNW

28

新しい読者への注意。
元の質問はSTLコンテナに関するものでした(特にstd :: mapに関するものではありません)

ほとんどのコンテナにはconstバージョンの演算子[]があることに注意してください。
std :: mapとstd :: setにはconstバージョンがないというだけで、これはそれらを実装する基礎となる構造の結果です。

std :: vectorから

reference       operator[](size_type n) 
const_reference operator[](size_type n) const 

また、2番目の例では、要素が見つからないかどうかを確認する必要があります。

void MyClass::MyFunction( int x ) const
{
    MyMap iter = m_map.find(x);
    if (iter != m_map.end())
    {
        std::cout << iter->second << std::endl
    }
}

1
std::set全く持っていませんoperator[]
全員

2

operator []はコンテナに新しい要素を挿入する可能性があるため、constメンバー関数にすることはできません。operator []の定義は非常に単純であることに注意してください。m[k]は(*((m.insert(value_type(k、data_type())))。first))。secondと同等です。厳密に言えば、このメンバー関数は不要です。便宜上存在するだけです。


0

インデックス演算子は、読み取り専用コンテナ(STL自体には実際には存在しません)に対してのみconstである必要があります。

インデックス演算子は、値を調べるためだけに使用されるわけではありません。


6
問題は、たとえばconst、2つのオーバーロードされたバージョン(1つは1つ、もう1つは非)がないのはなぜかということです。conststd::vector
Pavel Minaev 2009

-2

std :: mapメンバー変数を可変であると宣言した場合

mutable std::map<...> m_map;

constメンバー関数内でstd :: mapの非constメンバー関数を使用できます。


15
しかし、これはひどい考えです。
GManNickG 2009

7
そうすれば、クラスのAPIは嘘になります。この関数は、const(メンバー変数を変更しないことを意味します)であると主張しますが、実際には、m_mapデータメンバーを変更している可能性があります。
runcible 2010年

2
mutablestd::mutex、キャッシュ、デバッグヘルパーなどのメンバーに使用できます。マップをキャッシュとして使用して、非常に高価なconst「ゲッター」機能を高速化する場合mutableは、許容されます。注意する必要がありますが、それ自体はひどい考えではありません。
マークラカタ2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.