1

C# コーダーは、ファイルからテキストを取得するための単純な C++ メソッドを作成しました。

static std::vector<std::string> readTextFile(const std::string &filePath) {
    std::string line;
    std::vector<std::string> lines;
    std::ifstream theFile(filePath.c_str());
    while (theFile.good()) {
    getline (theFile, line);
        lines.push_back(line);
    }
    theFile.close();
    return lines;
}   

このコードが効率的でないことはわかっています。テキスト行は、読み取られるときに 1 回コピーされ、値によって返されるときに 2 回コピーされます。

2 つの質問:

(1) このコードはメモリリークを起こしますか? (2) より一般的に、オブジェクトのコンテナーを値で返すと、メモリ リークが発生することがありますか? (オブジェクト自体がリークしないと仮定)

4

5 に答える 5

5
while (theFile.good()) {
 getline (theFile, line);
    lines.push_back(line);
}

効率は忘れてください。このコードは正しくありません。ファイルを正しく読み取れません。理由については、次のトピックを参照してください。

したがって、ループは次のように記述します。

while (getline (theFile, line)) {
    lines.push_back(line);
}

これで正解です。効率的にしたい場合は、最初にアプリケーションをプロファイリングします。最も多くの CPU サイクルを使用している部分を確認してみてください。


(1) このコードはメモリリークを起こしますか?

いいえ。

(2) より一般的に、オブジェクトのコンテナーを値で返すと、メモリ リークが発生することがありますか?

コンテナー内のオブジェクトのタイプによって異なります。あなたの場合、オブジェクトのタイプstd::vectorは、std::stringメモリがリークしないことを確認するものです。

于 2012-08-30T19:59:36.177 に答える
1

C ++ 11では、次のことができます。

std::vector<std::string> 
read_text_file(const std::string& path) 
{
    std::string line;
    std::vector<std::string> ans;
    std::ifstream file(path.c_str());

    while (std::getline(file, line))
       ans.push_back(std::move(line));

    return ans;
}

余分なコピーは作成されません。

C ++ 03では、余分なコピーを受け入れ、プロファイリングで指示された場合にのみ、それらを痛々しいほど削除します。

注:ファイルを手動で閉じる必要はありません。のデストラクタが自動的に閉じstd::ifstreamます。

注2:char型でテンプレート化できます。これは、状況によっては役立つ場合があります。

template <typename C, typename T>
std::vector<std::basic_string<C, T>>
read_text_file(const char* path)
{
    std::basic_string<C, T> line;
    std::vector<std::basic_string<C, T>> ans;
    std::basic_ifstream<C, T> file(path);

    // Rest as above
}
于 2012-08-30T20:16:16.440 に答える
1

いいえ、いいえ。値による戻りでは、メモリ リークは発生しません (コンテナとそこに含まれるオブジェクトが適切に作成されていると仮定します)。それ以外の方法では、かなり役に立たないでしょう。

そして、私はNawazが言ったことに二番目に、あなたのwhileループは間違っています。率直に言って、信じられないほど何度も目にしますが、そこには非常に多くの悪いアドバイスがあるに違いありません.

于 2012-08-30T20:03:03.863 に答える
1

(1) このコードはメモリリークを起こしますか?

いいえ

(2) より一般的に、オブジェクトのコンテナーを値で返すと、メモリ リークが発生することがありますか?

いいえ。コンテナーに格納されているメモリは、ポインターによって、またはリークするオブジェクトを介してリークする可能性があります。しかし、それは値によって返されることによって引き起こされることはありません。

このコードが効率的でないことはわかっています。テキスト行は、読み取られるときに 1 回コピーされ、値によって返されるときに 2 回コピーされます。

おそらくそうではありません。文字列のコピーが 2 つありますが、考えているものではありません。リターン コピーは C++03 で最適化される可能性が高く、C++11 では最適化によって取り除かれるか、移動 (安価) に変換されます。

2つの対応はむしろ次のとおりです。

getline (theFile, line);
lines.push_back(line);

1 行目はファイルからlineにコピーし、2 行目は からlineコンテナにコピーします。C++11 コンパイラを使用している場合は、2 行目を次のように変更できます。

lines.push_back(std::move(line));

文字列の内容をコンテナに移動します。または (C++03 でも有効)、次のように 2 行を変更できます。

lines.push_back(std::string()); // In most implementations this is *cheap*
                                // (i.e. no memory allocation)
getline(theFile, lines.back());

そして、読み取りの結果をテストする必要があります (読み取りが失敗した場合、最後の代替手段ではresize、最後の空の文字列を削除するために要素を 1 つ少なくするようにしてください。

于 2012-08-30T20:05:59.767 に答える
0

いいえ、コンテナを値で返すことでメモリ リークが発生することはありません。標準ライブラリ自体は、どのような場合でもメモリ リークしないように設計されています。実装にバグがある場合にのみ、メモリをリークできます。少なくとも、古い MSVCの文字列のベクトルにバグがありました。

于 2012-08-30T20:07:45.980 に答える