• ベストアンサー

STLのmapのキーの変更方法

// この時点でキーは"1,2,3,4,5"と並んでいる std::map< CString , int >::iterator it = m_mapNOKATA.find("3"); if( it != m_mapNOKATA ) { (*it).first = "9"; } というような使い方は出来るのでしょうか? また、これをした場合、 for( it = m_mapNOKATA.begin() ; it != m_mapNOKATA.end() ; ++it) { cout << (*it).first << endl; } とすると、結果は 1 2 4 5 9 となるのか、 1 2 9 4 5 となるのでしょうか? 上の結果が正しいように思えますが、だとしたら、キーを変更した時点で並べ替えが起きている? それとも、キーはinsert後はもう変更できなくて、erase→insertとしなくてはならないのでしょうか? 手元にSTL環境が無いので、確認できません。 どなたかお分かりの方がいらっしゃいましたら教えてください。 たぶん、multimapやsetでも結果は同じかと思います。

質問者が選んだベストアンサー

  • ベストアンサー
  • furyfox
  • ベストアンサー率56% (58/103)
回答No.1

>(*it).first = "9"; それは無理です。 std::mapはinsertの段階で昇順になるよう適切な位置に挿入されます。 >erase→insertとしなくてはならないのでしょうか? つまりそういう事です。 ところで試しにやってみました。 (*it).first = "9"; firstがconstオブジェクトなのでコンパイルエラーになりました。

racoon_asia
質問者

お礼

ありがとうございました。 求めていた答えを得ることが出来ました。 const扱いならば納得が行きます。

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (1)

  • amru05
  • ベストアンサー率63% (33/52)
回答No.2

 stlのmapなどはxtreeのBR-Treeを使用して実装されていますので、BR-Treeの動作を調べると疑問が解けると思います。  参考に良いURLがあったので見てみてください。 BR-Tree : 黒 赤 木  左右のバランスを取るtree構造で、検索が早い。データが挿入されるたびにバランスを取るので、その意味では毎回並び変えが発生しているとも言えますね。

参考URL:
http://www.geocities.jp/h2fujimura/mutter/tree/red-black-tree.html
racoon_asia
質問者

お礼

ありがとうございます。 大変勉強になりました。

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • STLのvectorの削除

    STLのvectorの削除を行う場合に vector<myclass> v; ・・・ v.erase(it); ・・・ というように削除するiteratorを渡しますが、 任意のインデックスのvectorを削除した場合は、 どのようにそのiteratorを取得するのでしょうか。 例えばv[5]を削除したのですが、 vector<myclass>::iterator it=v.begin(); for(int i=0;i<5;i++) it++; v.erase(it); というbegin()やend()からのインクリメント・デクリメントで取得するしかないのでしょうか? ご教示願います。

  • STLのvectorの削除

    たびたび申し訳ありませんが、ご教示願います。 vector配列をeraseを使用して削除しているのですが、 どうしてもうまくいかず躓いています。 仮にvectorのサイズが3で1番目の要素を削除したいのですが、 どうしても、サイズに関わらず最後の要素が削除されてしまいます。 下記のコードのように簡略化しましたが、結果は変わりませんでした。 vector<class>obj; vector<class>::iterator it; ・・・ it=obj.begin(); it=obj.erase(it); 結果は最後の要素(サイズが3であれば3番目の要素)が削除されます。 erase時点でのitは削除したい要素をさしているのは確認済みです。 eraseの戻り値も削除したい要素を指してしまっています・・・・ なぜ最後の要素が削除されてしまうのでしょうか。 全く分かりません。よろしくお願いします。

  • STL mapからの要素の削除

    mapより特定の値を持つ要素を削除したいのですが、上手くいきません。 下のようなコードで実現しようとしたのですが、eraseを呼んだ次のループでもう一度eraseを呼んで実行時エラーとなってしまうようです。 erase後のイテレータが指す値が悪いのではないかとは思うのですが、実際に何が悪いのかご存知の方がいらっしゃればアドバイスをお願いいたします。 string s[20]; char c='a'; map<string,bool> m; //mapへの要素の挿入 for(int j=0;j<20;j++){ s[j]=string(&c); c++; if(j%10==0) m[s[j]]=true; else m[s[j]]=false; } map<string,bool>::iterator i; //削除処理 for(i=m.begin();i!=m.end();i++){ if(i->second){ m.erase(i); } }

  • map(STL)でinsertを行いたいですが、成功できないでいます。

    皆さん、こんにちは。 このほど、STLのMAPを勉強しだしたものですが、 もっと基本的な、 C++の事でつまずいてしまいました。 keyとvalueのセットを 登録したり、 取得したりするソースを書いています。 下記ソースにありますとおり、 getの指示を出した際は、 通常、find(key)を行い、 valueを得るのですが、 仮にfindにて意図するvalueが見つからなかった場合には、 MySQLから意図するkeyに対応するvalueを 取ってこようと思っています。 そして、MySQLからvalueを取得した後は、 「m1.insert」にて 取得したその「value」と「key」のセットを insertを行う事で、 コンテナに登録作業をしたいつもりなのです。 どんな1行を足せばいいでしょうか? ずばりの答えでなく、 ユルメな方針のアドバイスでも いただけるとありがたいです。 ================================================================= virtual void put(key_type key, value_type val) { m1.insert(std::make_pair(key, val)); } virtual void get(key_type key) { typename container_type::iterator iterator = m1.find(key); if (iterator != m1.end()) { CTL_INFO("", "[info] Got the value ."); } else { /* ここでMySQLへ接続を行う*/ char query[256]; std::stringstream keystream ; keystream << key; std::string key1 = keystream.str().c_str(); if(sprintf(query, "select value_dht from table_name where key = ('%s')",keystream.str().c_str())); mysql_query(conn, query); res = mysql_use_result(conn); //get the results while ((row = mysql_fetch_row(res)) != NULL){ std::stringstream keydb2stream ; key2stream << row[0] ; std::string val1 = key2stream.str().c_str(); } /* ここで、MySQLから得たvalについて、      上記「virtual void put」のように「m1.insert」を行いたい。 それにより、returnで再度virtual void getへ移動した際には、     「m1.find(key)」を成功させたいです。*/ } return 0; }; ================================================================= また、間違っているかもしれませんが、 試しに、 「return 0」の2行上で、 次の1行を入れてみたのですが、 コンパイル時にエラーが出て怒られて失敗をしてしまいました。 「virtual void put」の部分で行っているinsertと、 同じ内容の文字列を同じようにinsertしているのに、 今回は怒られてしまうのかも、 よく分かりませんでした。 的外れな対応でしたらすいません。 ======================================================== m1.insert(std::make_pair(keystream.str().c_str(), key2stream.str().c_str())) ======================================================== error: cannot convert ‘const char*’ to ‘sc::basic_message_cons<sc::basic_message<void, char> >*’ in initialization

  • テンプレートクラスとSTLを利用したMyListクラス

    こんにちは。STLのリストを使い自分だけのMyListクラスを作ろうとしたのですが、コンパイルできません。 エラーメッセージは警告 std::list<T>::iterator' : 依存名は型ではありません。 とでます。 ご教授お願いします。 #include<list> #include<iterator> template <class T> class CMyList { public: CMyList(); //virtual ~CMyList(); //bool HasNext(); //T Next(); //void Pushback( T t ); //void EraseCheck(); //T GetFirst(); private: std::list< T > m_List; std::list< T >::iterator m_It;//コンパイルエラー }; template <class T> CMyList<T>::CMyList() { m_List.clear(); std::list< T > ::iterator it = m_List.begin();//こう宣言する分にはOK m_It = m_List.begin(); } int main() { CMyList<int> m_List; return 0; }

  • テンプレートについて

    最近テンプレートを勉強し始めました。 試しに次のような関数を書いたのですがコンパイルエラーが出ます。 template<class T> void pirntAll(T t) { T::iterator p; for(p=t.begin();p!=t.end();p++) cout<<*p<<" "; cout<<endl; } エラーメッセージを見るとT::iterator p;のところがダメらしく pが定義されていないと叱られます。 結局本などを参考にして次のように書き換えました。 template<class InputIterator> void printAll(InputIterator first,InputIterator last) { while(first!=last) { cout<<*first<<" "; first++; } cout<<endl; } しかしprintAll()を使うとき1つめの定義ならprintAll(x);と書けますが 2つめの定義だとprintAll(x.begin(),x.end());と書かなくてはならないので 面倒です。そこで2つめの定義と次の関数を組み合わせることで、コンパイルも通り、 使うときもprintAll(x);と書けるようにしました。 template<class T> void printAll(T t) { printAll(t.begin(),t.end()); } 一応問題は解決したのですが何かひどく冗長なことをやらされているようで 気分が悪いです。なんとか1つめのような書き方ができないものでしょうか。 または1つめの書き方が出来ない(T::iteratorが使えない)正当な理由が あるなら教えてください。

  • C++ 文字列とポインタ、STL::mapについて

    C++でポインタと文字列の受け渡しについて質問です。 MyData::search()は文字列を受け取ってメンバ変数 dict内の ヒットしたデータの グループ(文字列)を返すメンバ関数です。 メンバ変数 dict はSTLのmapを使っています。 void MyData::search( const char* funcbox, const char* result ){ for ( map<const char*, const char*>::iterator itr = dict.begin(); itr != dict.end(); ++itr ){ const char* a_name = itr->first; const char* a_group = itr->second; if ( strstr( a_name, funcbox) ){ result = a_group; return; } } result = NULL; } MyData::dict["yamada"] = "groupA"; const char* res = NULL; MyData::search("yamada", res); cout << " group = " << res << endl; 上のようにアクセスするとメンバ関数内では res == "groupA" となりますが、 関数から出るとresはNULLになってしまいます。 res に関数を抜けた後も消えないアドレスを渡すにはどうすればよいでしょうか?

  • 新たに定義したクラスでmapを作成する場合

    STLのmapを使っているのですが、自分で定義したクラス(便宜上Keyと書きます)をキーにすると想定した動作になりません。 insert、iteratorによる参照はできるのですが、findがうまくいっていないようです。 値を見ると探しているキーと同じものが入っているのですが、2つのKeyのインスタンスが同一であるということが認識されていないのかfindの結果は(mapの名前).end()になってしまいます。 Keyのオペレータとして'<'は定義しましたが、「同一である」ことを示すために別のオペレータを定義する必要があるのでしょうか? あてずっぽうで'=='を定義してみましたがうまくいきません。 お知恵を拝借できればと思います。よろしくお願いします。

  • C++のSTL mapを使用するとセグメンテーション違反となる

    こんにちは。C++でSTLのmapの簡単な使用テストを以下のプログラムで行っており、動作確認ができました。 /* Assoc_array.c */ #define MAIN // (#include省略) using namespace std; namespace Usefuls { class Assoc_array_str { private: map<string, string> _h; public: void set(string key, string val); string get(string key); }; void Assoc_array_str::set(string key, string val){ _h.insert(pair<string, string>(key, val)); } string Assoc_array_str::get(string key){ map<string, string>::iterator p; p = _h.find(key); return p->second; } } #ifdef MAIN int main(){ Usefuls::Assoc_array_str assoc; assoc.set("Konnichiwa", "Hello"); cout << assoc.get("Konnichiwa") << endl; return 0; } #endif /* ここまで */ しかし、これを以下のように他のファイルから呼び出すと(先頭の#define MAINを#undef MAINに変えます)、「セグメンテーション違反です」というメッセージが出てしまいます。 /* Aa_test1.c */ #include <iostream> using namespace std; namespace Usefuls { class Assoc_array_str { public: void set(string, string); string get(string); }; } int main(){ Usefuls::Assoc_array_str assoc; assoc.set("Konnichiwa", "Hello"); cout << assoc.get("Konnichiwa") << endl; return 0; } /* ここまで */ コンパイル方法は以下の通りです。 g++ -c Assoc_array.c g++ Aa_test1.c Assoc_array.o また、使用プラットホームはLinuxのCentOS 4.3です。 原因が分かる方、ご回答をよろしくお願いします。

  • listをvectorにコピーするときに

    例えば #include<iostream> #include<vector> #include<list> using namespace std; void main(void) { unsigned pos; list<unsigned> lu; list<unsigned>::iterator p; vector<unsigned> vu; for(lu.clear(),pos=0;pos<9;lu.push_back(pos++)); for(p=lu.begin();p!=lu.end();cout<<*p++); cout<<endl; vu=vector(lu); //error for(pos=0;pos<vu.size();cout<<vu[pos++]); cout<<endl; } とするとエラーになるため//errorのかわりに vu.clear(); vu.insert(vu.begin(),lu.begin(),lu.end()); としていますが少し不細工です 他に方法はあるのでしょうか?