web-dev-qa-db-ja.com

C ++で文字列でいっぱいのstd :: mapを反復処理する方法

std::mapを使用して定義された文字列の連想配列の繰り返しに関連する次の問題があります。

-- snip --
class something 
{
//...
   private:
      std::map<std::string, std::string> table;
//...
}

コンストラクターで、文字列データに関連付けられた文字列キーのペアをテーブルに追加します。他のどこかに、テーブルオブジェクトに含まれるすべてのキーと関連データを含む文字列オブジェクトを返すメソッドtoStringがあります(key = data形式として)。

std::string something::toString() 
{
        std::map<std::string, std::string>::iterator iter;
        std::string* strToReturn = new std::string("");

        for (iter = table.begin(); iter != table.end(); iter++) {
           strToReturn->append(iter->first());
           strToReturn->append('=');
           strToRetunr->append(iter->second());
           //....
        }
       //...
}

コンパイルしようとすると、次のエラーが表示されます。

error: "error: no match for call to ‘(std::basic_string<char,
    std::char_traits<char>, std::allocator<char> >) ()’".

誰かが不足しているもの、私が間違っていることを私に説明できますか?ユーザーがhash_mapオブジェクトでhash_mapを使用できるようにするためにハッシュ関数を定義する必要があるstd::stringの場合に、同様の問題に関するいくつかの議論を見つけました。私の場合も似たようなものでしょうか?

62
crazybyte

主な問題は、イテレータでfirst()というメソッドを呼び出すことです。あなたがすることは、firstというプロパティを使用することです:

...append(iter->first) rather than ...append(iter->first())

スタイルの問題として、newを使用してその文字列を作成しないでください。

std::string something::toString() 
{
        std::map<std::string, std::string>::iterator iter;
        std::string strToReturn; //This is no longer on the heap

        for (iter = table.begin(); iter != table.end(); ++iter) {
           strToReturn.append(iter->first); //Not a method call
           strToReturn.append("=");
           strToReturn.append(iter->second);
           //....
           // Make sure you don't modify table here or the iterators will not work as you expect
        }
        //...
        return strToReturn;
}

編集: facildelembrarは(コメントで)最近のC++ではループを書き換えることができると指摘しました

for (auto& item: table) {
    ...
}
73
Tom Leys
  1. toString()メソッドを記述しないでください。これはJavaではありません。クラスにストリーム演算子を実装します。

  2. 独自のループを記述するよりも、標準アルゴリズムを使用することをお勧めします。この状況では、std::for_each()は、あなたがしたいことへの素晴らしいインターフェースを提供します。

  3. ループを使用する必要があるが、データを変更するつもりがない場合は、iteratorよりもconst_iteratorを優先してください。そうすれば、誤って値を変更しようとすると、コンパイラーは警告を出します。

次に:

std::ostream& operator<<(std::ostream& str,something const& data)
{
    data.print(str)
    return str;
}

void something::print(std::ostream& str) const
{
    std::for_each(table.begin(),table.end(),PrintData(str));
}

次に、それを印刷したい場合は、オブジェクトをストリームします:

int main()
{
    something    bob;
    std::cout << bob;
}

オブジェクトの文字列表現が実際に必要な場合は、lexical_castを使用できます。

int main()
{
    something    bob;

    std::string  rope = boost::lexical_cast<std::string>(bob);
}

記入する必要がある詳細。

class somthing
{
    typedef std::map<std::string,std::string>    DataMap;
    struct PrintData
    {
         PrintData(std::ostream& str): m_str(str) {}
         void operator()(DataMap::value_type const& data) const
         {
             m_str << data.first << "=" << data.second << "\n";
         }
         private:  std::ostream& m_str;
    };
    DataMap    table;
    public:
        void something::print(std::ostream& str);
};
19
Martin York

次のように追加呼び出しを変更します

...append(iter->first)

そして

... append(iter->second)

さらに、行

std::string* strToReturn = new std::string("");

ヒープに文字列を割り当てます。この動的に割り当てられた文字列へのポインタを実際に返す場合は、戻り値をstd :: string *に変更する必要があります。

あるいは、ヒープ上のオブジェクトの管理を気にしたくない場合は、ローカル宣言を

std::string strToReturn("");

参照構文を使用するように「追加」呼び出しを変更します...

strToReturn.append(...)

の代わりに

strToReturn->append(...)

これにより、スタック上に文字列が作成され、その後copyが戻り変数に格納されることに注意してください。これはパフォーマンスに影響します。

4
Adam Holmberg

iter->firstおよびiter->secondは変数です。これらをメソッドとして呼び出そうとしています。

2
Nick Lewis

Std :: map :: iteratorの間接参照の結果は std :: pair であることに注意してください。 firstsecondの値は関数ではなく、変数です。

変化する:

iter->first()

iter->first

iter->secondと同じ。

2
E.M.

つかいます:

std::map<std::string, std::string>::const_iterator

代わりに:

std::map<std::string, std::string>::iterator
1
Dzwiedziu-nkg

別の価値のある最適化は、c_str() STL stringクラスのメンバーです。これは、[〜# 〜] lpctstr [〜#〜]、e。 g。、LPCTSTRを期待するカスタム関数。私はそれを確認するためにデストラクタをたどっていませんが、文字列クラスはコピーを作成するメモリを管理していると思われます。

0
David A. Gray

c ++ 11では、使用できます

for ( auto iter : table ) {
     key=iter->first();
     value=iter->second();
}
0
james