2012-05-21 4 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에 의지하여'close'를 호출하지 않습니다.하지만 운좋게도 강력한 IO를 수행하지 않는 코드를 작성하면됩니다. –

+0

@ KonradRudolph : RAII에 의존하는 것은 소멸자가 클로징이 성공했는지 여부를 테스트하지 않는다는 것을 의미합니다. 전역 변수를 사용하지 않는 한 이러한 오류 조건을 호출자에게 전송할 수단이 없습니다. –

+0

@Frerich 물론. 내가 말했듯이, 나는 강건하지 않은 IO를 수행하는 것으로 벗어날 수 있습니다. 게으른, 나도 알아,하지만 코드를 훨씬 간단하고 깨끗하게. –

2

이이 성하지 어떻게 연무가 사용되기로되어 있습니다. 사실,이 (불행히도!) 컴파일하고 심지어 "옳은"일을합니다. 그러나 이와 같은 코드를 작성하지 마십시오. 이 코드를 작성한 사람은 누구나 그들이 영리하다고 생각했을 것입니다.

하지만 실제로 그들이 한 일은 진정한 장점이없는 새롭고 독창적 인 API를 도입하여 C++ 프로그래머의 기대를 깨뜨리는 것이 었습니다.

이 코드는 Person 유형의 객체를 입력 스트림에서 초기화합니다. 불행히도이 작업을 통해 코드는 객체를 읽는 동안 오류를 테스트 할 수있는 기회를 얻지 못합니다. 이것은 좋지 않다. 객체가 이 아니고에 생성자가 입력 스트림을 허용해야하는 경우에는 operator>>을 오버로드해야합니다.

+0

악마 옹호자를 여기에서 놀기 : 생성자에게 스트림을 전달하는 것이 완벽하다고 생각합니다. 예외를 사용하여 오류를 알리고 개체를 초기화 할 수 없게되는 문제를 피할 수 있습니다 (대안을 제시 한 것과 달리 개체를 만들 수 있지만'연산자 >> '는 사용하지 않습니다). –

+0

@Frerich 원칙적으로 전적으로 당신에게 동의합니다. 그래서 이것이 프로그래머가 영리하다고 말한 이유입니다. 제임스가 스트림에 대해 우둔하다고 생각한 프로그래머가 아니라 영리한 프로그래머였습니다. 그러나 여전히 기대를 깨고 C++에서 기존의 스트림 라이브러리의 맨 위에있는 좋은 아이디어는 아닙니다. 스트림은 훨씬 더 잘 수행 될 수 있지만 자체 라이브러리를 빌드하고 다르게 작동하는 기존 패턴 위에 빌드하지 마십시오. –