5

パフォーマンスのオーバーヘッドはどれくらいか知りたいのですが

string line, word;
while (std::getline(cin, line))
{
    istringstream istream(line);
    while (istream >> word)
        // parse word here
}

c++これが入力をトークン化する標準的な方法だと思います。

具体的には:

  • getline各行は、最初に、次にistreamコンストラクターを介して、最後operator>>に各単語に対してを介して、 3回コピーされますか?
  • 頻繁な建設と破壊がistream問題になるでしょうか?istream外側のwhileループの前に定義した場合の同等の実装は何ですか?

ありがとう!

アップデート:

同等の実装

string line, word;
stringstream stream;
while (std::getline(cin, line))
{
    stream.clear();
    stream << line;
    while (stream >> word)
        // parse word here
}

ストリームをローカルスタックとして使用し、行をプッシュして単語をポップアウトします。これにより、以前のバージョンで頻繁に発生したコンストラクタとデストラクタの呼び出しがなくなり、ストリームの内部バッファリング効果が利用されます(この点は正しいですか?)。

代替ソリューションは、std :: stringを拡張してoperator<<およびをサポートoperator>>するか、iostreamを拡張してsthをサポートする場合があります。のようにlocate_new_lineここでブレインストーミングをします

4

2 に答える 2

7

残念ながら、iostream はパフォーマンスを重視する作業には適していません。問題は、メモリ内のものをコピーすることではなく (文字列のコピーは高速です)、仮想関数のディスパッチであり、文字ごとにいくつかの間接関数呼び出しを調整する可能性があります。

コピーに関する質問については、はい、書かれているように、 new を初期化するとすべてがコピーされますstringstreamgetline(また、文字はまたはによってストリームから出力文字列にコピーされます>>が、これは明らかに防止できません。)

C++11 のmove機能を使用すると、不要なコピーを削除できます。

string line, word;
while (std::getline(cin, line)) // initialize line
{       // move data from line into istream (so it's no longer in line):
    istringstream istream( std::move( line ) );
    while (istream >> word)
        // parse word here
}

とはいえ、パフォーマンスが問題になるのは、測定ツールがそうであると判断した場合のみです。Iostreams は柔軟で堅牢であり、filebuf基本的に十分に高速であるため、コードをプロトタイプ化して機能させ、すべてを書き直すことなくボトルネックを最適化できます。

于 2012-06-09T14:29:50.330 に答える
1

ブロック内で変数を定義すると、その変数はスタックに割り当てられます。ブロックを離れるとき、スタックからポップされます。このコードを使用すると、スタックで多くの操作を行うことができます。これは「単語」にも当てはまります。変数の代わりにポインターを使用してポインターを操作できます。ポインタもスタックに格納されますが、ポインタが指している場所はヒープメモリ内の場所です。

このような操作では、変数を作成し、スタックにプッシュして、スタックから再度ポップするためのオーバーヘッドが発生する可能性があります。ただし、ポインタを使用すると、スペースを1回割り当て、ヒープ内の割り当てられたスペースを操作します。また、ポインタは実際のオブジェクトよりもはるかに小さい可能性があるため、ポインタの割り当てが速くなります。

ご覧のとおりgetLine()、メソッドはオブジェクトへの参照(ある種のポインタ)を受け入れline、文字列オブジェクトを再度作成せずにメソッドを機能させます。

コードではlineword変数が1回作成され、それらの参照が使用されます。各反復で作成している唯一のオブジェクトはss変数です。各反復で作成したくない場合は、ループの前に作成し、relatesメソッドを使用して初期化できます。コンストラクターを使用せずに、再割り当てするための適切なメソッドを検索して見つけることができます。

あなたはこれを使うことができます:

string line, word ;
istringstream ss ;
while (std::getline(cin, line))
{
    ss.clear() ;
    ss.str(line) ;
    while (ss >> word) {
        // parse word here
    }
}

また、このリファレンスistringstreamを使用できます

編集:コメント@jrokをありがとう。はい、新しい文字列を割り当てる前にエラーフラグをクリアする必要があります。これはstr()istringstream::strのリファレンスです

于 2012-06-09T13:04:45.503 に答える