web-dev-qa-db-ja.com

std :: map、マップキー値へのポインタ、これは可能ですか?

std::map<std::string, std::string> myMap;

std::map<std::string, std::string>::iterator i = m_myMap.find(some_key_string);
if(i == m_imagesMap.end())
    return NULL;

string *p = &i->first;

最後の行は有効ですか?このポインタpを別の場所に保存したいのですが、プログラム全体で有効ですか?しかし、このマップに(他の一意のキーを使用して)要素を追加したり、他のキーを削除したりすると、この文字列(キーと値のペア)が再割り当てされ、pが無効になります。

24
michael

まず、マップは安定していることが保証されています。つまり、イテレータは要素の挿入または削除によって無効になりません(もちろん削除される要素を除く)。

ただし、イテレータの安定性はポインタの安定性を保証するものではありません。通常、ほとんどの実装では、イテレータを実装するために(少なくともある程度のレベルで)ポインタを使用することがありますが(つまり、ソリューションが機能すると想定するのは非常に安全です)、実際に格納する必要があるのはイテレータ自体です

あなたができることは、次のような小さなオブジェクトを作成することです。

struct StringPtrInMap
{
  typedef std::map<string,string>::iterator iterator;
  StringPtrInMap(iterator i) : it(i) {}
  const string& operator*() const { return it->first; }
  const string* operator->() const { return &it->first; }
  iterator it;
}

そして、文字列ポインタの代わりにそれを保存します。

20
PierreBdR

セクション23.1.2#8(関連コンテナ要件):

挿入メンバーは、イテレーターとコンテナーへの参照の有効性に影響を与えないものとし、消去メンバーは、イテレーターと消去された要素への参照のみを無効にするものとします。

したがって、yes map要素のデータメンバーへのポインタの格納は、that要素を削除しない限り、有効であることが保証されます。

52
Greg Rogers

どの操作がイテレータを無効にするかわからない場合は、 参照 で簡単に調べることができます。たとえば、 vector :: insert の場合、次のようになります。

これにより、ベクトルサイズが効果的に増加し、新しいベクトルサイズが現在のベクトル容量を超えた場合にのみ、割り当てられたストレージスペースが自動的に再割り当てされます。ベクトルコンテナでの再割り当ては、以前に取得したすべてのイテレータ、参照、およびポインタを無効にします。

map :: insert 一方、その種のことは何も言及していません。

ただし、Pierreが言ったように、ポインタではなくイテレータを格納する必要があります。

1
drby

なぜあなたはこれをしたいのですか?

* pの値はconststd :: stringであるため、変更できません。変更した場合は、要素の並べ替え順序を変更することで、コンテナーの不変条件を壊す可能性があります。

ここで指定していない他の要件がない限り、文字列のコピーを取得する必要があります。

0
Richard Wolf