2012-05-21 24 views
6
class Person { 
private: 
    string firstName; 
    string lastName; 
public: 
    Person() {} 

    Person(ifstream &fin) { 
     fin >> firstName >> lastName; 
    } 

    void print() { 
     cout << firstName 
      << " " 
      << lastName 
      << endl; 
    } 
}; 

int main() { 
    vector<Person> v; 
    ifstream fin("people.txt"); 

    while (true) { 
     Person p(fin); 
     if (fin == NULL) { break; } 
     v.push_back(p); 
    } 

    for (size_t i = 0; i < v.size(); i++) { 
     v[i].print(); 
    } 

    fin.close(); 
    return 0; 
} 

次のコードスニペットの仕組みを教えてください。 if(fin == NULL){break; }C++、ifstreamを使用してファイルを読み取る

フィンはポインタではなくスタック上のオブジェクトなので、NULLになることはできません。 ifstreamクラスでオーバーロードされた演算子==関数が見つかりませんでした。 このスニペットの仕組みを理解できません。

答えて

5

ifstreamクラスはoperator void *() (or operator bool() in C++11)です。これは、(fin == NULL)をテストするときに呼び出されるものです。

テストfin == NULLは、テストfin.fail()とまったく同じです。

+0

ありがとうございます。 あなたの答えはとても役に立ちました。 – Yoh0xFF

3

istreamostreamの基底クラスには、ブール値として使用できる暗黙の変換 関数があります。 pre-C++ 11では で暗黙の変換はvoid*になりました。

なお、この変換の結果は ポインタとして使用されることが意図はなかった、とfin == NULLようなコードは、C++標準のストリームの極めて乏しい 理解を示しています。最初のループを書く の慣用的な方法は、デフォルトコンストラクタとPersonため operator>>を定義することで、次に書きます:私はそれをしていながら

Person p; 
while (fin >> p) { 
    v.push_back(p); 
} 

(そして:あなたは本当に戻り値をテストする必要がありますそれが失敗した場合 fin.close()の、および0を返さない:。

fin.close(); 
return fin ? EXIT_SUCCESS : EXIT_FAILURE; 

+0

私はそれを行うのがベストプラクティスであると私は同意しますが、私は決して成功したかどうかをテストし、戻り値を調整するコードは見たことがありません。個人的には、とにかくRAIIに頼っているとは決して決してクローズしませんが、幸いなことに堅牢なIOをしないコードを書くことができます。 –

+0

@ KonradRudolph:RAIIに頼っているのは、デストラクタがクローズが成功したかどうかをテストしないことを意味します。このようなエラー条件を呼び出し元に伝える手段はありません(グローバル変数に依存しない限り)。 –

+0

@Frerichもちろん。私が言ったように、私は非堅牢なIOをやることで逃げることができます。レイジー、私は知っているが、それはコードをはるかに単純できれいにする。 –

2

これはSTの方法ではありませんリームが使用されるはずです。確かに、これは(残念ながら!)コンパイルし、 "正しい"ことさえします。しかし、このようなコードを書かないでください。このコードを書いた人はおそらく彼らが賢いと思ったでしょう。

しかし、彼らが本当にしたことは、本当の利点がない、新しい、独創的でないAPIを導入することによって、C++プログラマーの期待を破ったことでした。

このコードは、タイプPersonのオブジェクトを入力ストリームから初期化します。残念なことに、これを行うことで、コードはオブジェクトを読み取っている間にエラーをテストする機会を忘れることになります。これは良くありません。オブジェクトはではなく、には入力ストリームを受け入れるコンストラクタがある必要があります。オーバーフローするのはoperator>>です。

+0

ここで悪魔の擁護者を演じる:私はコンストラクタにストリームを渡すことが理にかなっていると思います。エラーを通知するために例外を使うことができ、オブジェクトの初期化ができないという問題を避けることができます(オブジェクトの作成は可能ですが、 'operator >> 'を使用しないでください)。 –

+0

@Frerich原則として、私はあなたに完全に同意します。それはまた、私は、プログラマーが賢明であると言いました。なぜならジェームスは、それが流れについて無知だと思っていたからです。しかし、それはまだ期待を破り、おそらくC++で既存のストリームライブラリーの上に構築するのは良い考えではありません。ストリームははるかに良い結果が得られるかもしれませんが、独自のライブラリを構築し、別の方法で動作する既存のパターンの上に構築しないでください。 –

関連する問題