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
の場合に、同様の問題に関するいくつかの議論を見つけました。私の場合も似たようなものでしょうか?
主な問題は、イテレータで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) {
...
}
toString()
メソッドを記述しないでください。これはJavaではありません。クラスにストリーム演算子を実装します。
独自のループを記述するよりも、標準アルゴリズムを使用することをお勧めします。この状況では、std::for_each()
は、あなたがしたいことへの素晴らしいインターフェースを提供します。
ループを使用する必要があるが、データを変更するつもりがない場合は、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);
};
次のように追加呼び出しを変更します
...append(iter->first)
そして
... append(iter->second)
さらに、行
std::string* strToReturn = new std::string("");
ヒープに文字列を割り当てます。この動的に割り当てられた文字列へのポインタを実際に返す場合は、戻り値をstd :: string *に変更する必要があります。
あるいは、ヒープ上のオブジェクトの管理を気にしたくない場合は、ローカル宣言を
std::string strToReturn("");
参照構文を使用するように「追加」呼び出しを変更します...
strToReturn.append(...)
の代わりに
strToReturn->append(...)
これにより、スタック上に文字列が作成され、その後copyが戻り変数に格納されることに注意してください。これはパフォーマンスに影響します。
iter->first
およびiter->second
は変数です。これらをメソッドとして呼び出そうとしています。
Std :: map :: iteratorの間接参照の結果は std :: pair であることに注意してください。 first
とsecond
の値は関数ではなく、変数です。
変化する:
iter->first()
に
iter->first
iter->second
と同じ。
つかいます:
std::map<std::string, std::string>::const_iterator
代わりに:
std::map<std::string, std::string>::iterator
別の価値のある最適化は、c_str() STL stringクラスのメンバーです。これは、[〜# 〜] lpctstr [〜#〜]、e。 g。、LPCTSTRを期待するカスタム関数。私はそれを確認するためにデストラクタをたどっていませんが、文字列クラスはコピーを作成するメモリを管理していると思われます。
c ++ 11では、使用できます
for ( auto iter : table ) {
key=iter->first();
value=iter->second();
}