2012-05-21 36 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; 
} 

Per favore, puoi spiegarmi come funziona lo snippet di codice seguente? if (fin == NULL) {break; }C++, lettura di un file utilizzando ifstream

pinna è un oggetto in pila, non un puntatore quindi non può diventare NULL. Impossibile trovare la funzione == dell'operatore sovraccarico nella classe ifstream. Quindi non riesco a capire come funziona questo frammento.

risposta

5

La classe ifstream ha un operator void *() (or operator bool() in C++11). Questo è ciò che viene chiamato quando si prova (fin == NULL).

Il test fin == NULL deve essere esattamente lo stesso del test fin.fail().

+0

Grazie mille. La tua risposta è stata molto utile. – Yoh0xFF

3

Le classi base di istream e ostream hanno funzioni di conversione implicita che consentono di utilizzarle come valore booleano; in pre-C++ 11, la conversione implicita era a void*.

non era mai l'intento che il risultato di questa conversione essere usato come un puntatore , e il codice come fin == NULL mostra estremamente scarsa comprensione C++ ei flussi standard. Il modo idiomatico di scrivere il primo ciclo sarebbe quello di definire un costruttore di default ed un operator>> per Person, e poi scrivere:

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

(E mentre io sono a esso: davvero dovrebbe verificare il valore di ritorno di fin.close(), e non tornare 0 se fallisce:.

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

)

+0

Anche se sono d'accordo sul fatto che probabilmente sarebbe meglio farlo, non ho mai ** visto il codice che verifica se la chiusura è andata a buon fine e aggiustando il valore di ritorno. Personalmente, non chiamo mai "chiudi" in ogni caso, basandomi su RAII, ma fortunatamente posso scappare scrivendo un codice che non fa IO robusto. –

+0

@KonradRudolph: Suppongo che fare affidamento su RAII implichi che il distruttore non verifica se la chiusura ha avuto esito positivo. Non ci sono mezzi per trasportare una tale condizione di errore al chiamante (a meno che non si ricorra a variabili globali). –

+0

@Frerich Naturalmente. Come ho detto, posso fare a meno di fare IO non robusto. Pigro, lo so, ma rende il codice molto più semplice e più pulito. –

2

Questo non è il modo st le risme dovrebbero essere usate. È vero, questo (purtroppo!) Compila e fa persino la cosa giusta. Ma non scrivere codice come questo. Chiunque abbia scritto questo codice probabilmente ha pensato che fossero intelligenti.

Ma quello che hanno fatto è stato di rompere le aspettative dei programmatori C++ introducendo una nuova API non convenzionale, senza reali vantaggi.

Questo codice inizializza un oggetto di tipo Person da un flusso di input. Sfortunatamente, facendo ciò, il codice rinuncia all'opportunità di verificare gli errori durante la lettura dell'oggetto. Questo non va bene. Un oggetto deve non avere un costruttore che accetta un flusso di input, deve sovraccaricare operator>>.

+0

Suonare i diavoli avvocato qui: Penso che passare un flusso a un costruttore abbia perfettamente senso. Puoi usare le eccezioni per segnalare errori ed evitare il problema di avere la possibilità di oggetti non inizializzati (diversamente dalla tua alternativa suggerita, che permette di costruire un oggetto ma non di usare l'operatore >>). –

+0

@Frerich In linea di principio, sono completamente d'accordo con te. Questo è anche il motivo per cui ho detto che si trattava di un programmatore intelligente, piuttosto che di James che pensava che fosse qualcuno che non conosceva i flussi. Ma rompe ancora le aspettative e probabilmente non è una buona idea in C++ basandosi sulla libreria del flusso esistente. Gli stream potrebbero essere fatti molto meglio, ma poi creare una propria libreria, non costruire su uno schema esistente che funzioni in modo diverso. –