1

以下のコードで文字列メモリをtmp再利用できるかどうか疑問に思っていました。そのメモリは反復ごとに再割り当てされますか? この種のケースに対処するためのより良い方法はありますか?

string s, line;
map<string, string> mymap;
while(getline(file, line) {
  if(a) s = "_a";
  else if(b) s = "_b";
  string tmp = line + s;
  mymap.insert(tmp, s);
}
4

3 に答える 3

4

tmpループの前後で毎回作成および破棄され、の文字列データのコピーを取得しlineます。したがって、次のように、安価で改善の可能性が高く、悪化する可能性はほとんどありません。

if(a) s = "_a";
else if(b) s = "_b";
line += s;
mymap.insert(line, s);

sタイプも指定します。リテラルのコピーのみが含まれるループごとに1回const char*を割り当てることはあまり意味がありません。ただし、への呼び出しによってstring変換されるため、どちらの方法でもそれほど多くはありません。stringinsert

コードの単純さ/可読性/保守性/設計を損なうことがなければ、改善の可能性が高く、悪化する可能性はほとんどありませんが、時期尚早の最適化ではありません。lineとの範囲が大きいほど、s読者/メンテナを誤解させる可能性があるため、それらを使ってトリックを実行するリスクが高くなります(それぞれ値の変更とタイプの変更)。これが、短い関数が優れている理由の1つです。

mymap.insert(std::move(line), s);C ++ 11では、別の簡単な可能性のある改善のために書くことができます。

とはいえ、不必要なコピーと割り当てをいくら行っても、それにかかる時間は、のI/Oの時間よりも短いことに気付くかもしれませんgetline。この場合、コードを書くための2つの非常によく似た方法があり、そのうちの1つはより効率的である必要があります。したがって、それを使用する方がよいかもしれませんが、それが必ずしも違いを生むと考えて過大評価しないでください。

于 2012-09-27T09:18:19.113 に答える
3

whileループを繰り返すたびに、文字列tmpオブジェクトが作成および破棄されます。したがって、最初のステップはtmp、すでに提案したように、whileループの外側に移動することです。そうすれば、反復ごとに新しい文字列オブジェクトを作成する必要がありません。tmp = line + sただし、反復ごとにメモリの再割り当てを引き起こす割り当てがまだあります。= operatorを使用すると、引数のコピーが作成され、そのコピーがtmp文字列オブジェクトに割り当てられます。したがって、2番目のステップは、文字列オブジェクトmymap.insert(line+s, s);の必要性を排除する提案を追加することです。tmp

反復ごとに割り当て"_a"たり"_b"文字列を作成したりしないことで、この改善を継続できると思います。sこれは、whileループの外側で一度実行でき、その後、内容に応じて、aさまざまbな文字列オブジェクトをマップに追加できます。このようなもの(nbこれはテストされていません):

string a = "_a";
string b = "_b";
string line;
map<string, string> mymap;
while(getline(file, line) {
  if(a) mymap.insert(line+a, a);
  else if(b) mymap.insert(line+b, b);
}

私の意見では、コードの可読性を維持しているので、juanchopanzaの答えで十分です。しかし、上記のコードではコピーが少なくなっていると思います。

于 2012-09-27T08:51:56.383 に答える
1

はい、C++ 11 標準で導入された STD::MOVE セマンティクスを使用します。

更新: 例

#include <iostream>
#include <utility>
#include <vector>
#include <string>
int main()
{
    std::string str = "Hello";
    std::vector<std::string> v;

    // uses the push_back(const T&) overload, which means 
    // we'll incur the cost of copying str
    v.push_back(str);
    std::cout << "After copy, str is \"" << str << "\"\n";

    // uses the rvalue reference push_back(T&&) overload, 
    // which means no strings will copied; instead, the contents
    // of str will be moved into the vector.  This is less
    // expensive, but also means str might now be empty.
    v.push_back(std::move(str));
    std::cout << "After move, str is \"" << str << "\"\n";

    std::cout << "The contents of the vector are \"" << v[0]
                                         << "\", \"" << v[1] << "\"\n";
}
于 2012-09-27T08:26:39.960 に答える