好きなおでんの具材ドラフト会議しましょう

C++のifstreamの使い方で分からない所があるので、分かる方御教示ください。
下記は、C++で読み込んだファイルの中身が空だった場合を無理やり例外処理を使って書いてみたのですが、中身が存在する場合、たとえば、

line1
line2
line3

ではline1を無限に繰り返してしまいます。(1)を

ifstream instream = inStream(argv[1]);
while (instream >> input)

にするとうまくいくようなのですが、この違いがよくわかりません。
違いを教えてください。


#include <iostream>
#include <string>
#include <fstream>
using namespace std;

ifstream inStream(char *str);

int main(int argc, char *argv[]) {
if (argc < 2)
cout << "ファイル名を指定してください" << endl;
else {
try {
string input;
while (inStream(argv[1]) >> input) // (1)
cout << input << endl;
}
catch (int i) {
cerr << argv[1] << "を開けません" << endl;
}
}
return 0;
}

ifstream inStream(char *str) {
ifstream inStream(str);
if (!inStream) throw 1;
return inStream;
}

A 回答 (2件)

ifstream inStream(str);



の行が、何をやっているか、理解してますか?

「strで指定されたファイルをストリームとしてオープンして、ファイルの読み込みポインタを先頭にする」のですよ。

そして

return inStream;

の行で、オープンしたストリームを「ifstream型の変数」として返しています。

なので

while (inStream(argv[1]) >> input)

とやると「毎回、argv[1]で指定されたファイルをオープンして、読み込み位置を1行目にする」ってのを繰り返します。

なので「何回ループしようが、1行目しか返って来ない」のです。

しかも、ストリームをクローズしないまま、何度も再オープンを繰り返しているので、何十回か繰り返した段階で、リソースを使い尽くしてオープンエラーが出る筈です。

ともかく「クローズしないでオープンを何度も繰り返す」ってのは、絶対に駄目です。

オープンしたストリームハンドラは「プログラム終了時に自動的にクローズされる」ので、明示的にクローズしない人が殆どですが、本来であれば「ストリームハンドラを変数に受け取って、最後にクローズするべき」なのです。

#include <iostream>
#include <string>
#include <fstream>
using namespace std;

ifstream inStream(char *str);

int main(int argc, char *argv[]) {
if (argc < 2)
cout << "ファイル名を指定してください" << endl;
else {
try {
string input;

//オープンしていいのは最初の1回だけ!
//ストリームハンドラは変数に受け取る
ifstream instream = inStream(argv[1]);

//受け取った変数でループを回す
while (instream >> input)
cout << input << endl;
}

//終わったらちゃんとクローズ!
instream.close();

//ここから例外処理
catch (int i) {
cerr << argv[1] << "を開けません" << endl;
}
}
return 0;
}

ifstream inStream(char *str) {
ifstream inStream(str);
if (!inStream) throw 1;
return inStream;
}
    • good
    • 0
この回答へのお礼

詳しい説明ありがとうございました。

お礼日時:2014/10/27 15:44

>ifstream instream = inStream(argv[1]);


>while (instream >> input)
>にするとうまくいくようなのですが、この違いがよくわかりません。
>違いを教えてください。

inStream()の中で「毎回、新規にオープンし直す」ので、結果として「毎回先頭から読み込んでいる」んです。
# 正確には…ローカル変数としてifstreamのインスタンス作成して…でしょうかね。
コードに書かれた通り、正常動作していますよ。
# ただし、オープンしたifstreamを閉じていないので、リソースリークしていると思いますが。


ってか…
>ifstream inStream(char *str) {
>ifstream inStream(str);
だと、再帰で永遠に自分呼び出ししません?(吹っ飛ぶまで)
# いや、ローカル変数名と関数名が同一だからコンパイルエラー?
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!


おすすめ情報