2010-03-08 17 views
7

Voici probablement une question très noobish: Comment (si possible) puis-je retourner un ifstream à partir d'une fonction?Renvoyer ifstream dans une fonction

Fondamentalement, j'ai besoin d'obtenir le nom de fichier d'une base de données de l'utilisateur, et si la base de données avec ce nom de fichier n'existe pas, alors je dois créer ce fichier pour l'utilisateur. Je sais comment faire cela, mais seulement en demandant à l'utilisateur de redémarrer le programme après avoir créé le fichier. Je voulais éviter cet inconvénient pour l'utilisateur si possible, mais la fonction ci-après ne compile pas gcc:

ifstream getFile() { 
    string fileName; 
    cout << "Please enter in the name of the file you'd like to open: "; 
    cin >> fileName; 
    ifstream first(fileName.c_str()); 
    if(first.fail()) { 
     cout << "File " << fileName << " not found.\n"; 
     first.close(); 
     ofstream second(fileName.c_str()); 
     cout << "File created.\n"; 
     second.close(); 
     ifstream third(fileName.c_str()); 
     return third; //compiler error here 
    } 
    else 
     return first; 
} 

EDIT: désolé, oublié de vous dire où et ce que l'erreur du compilateur a été:

main.cpp:45: note: synthesized method ‘std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const std::basic_ifstream<char, std::char_traits<char> >&)’ first required here 

EDIT: J'ai changé la fonction pour retourner un pointeur à la place comme Remus l'a suggéré, et changé la ligne dans main() en "ifstream database = * getFile()"; maintenant je reçois cette erreur à nouveau, mais cette fois dans la ligne principale():

main.cpp:27: note: synthesized method ‘std::basic_ifstream<char, std::char_traits<char> >::basic_ifstream(const std::basic_ifstream<char, std::char_traits<char> >&)’ first required here 
+3

Ce que vous avez listé n'est pas une erreur de compilation, c'est une "note". Regardez l'erreur réelle. –

Répondre

5
bool checkFileExistence(const string& filename) 
{ 
    ifstream f(filename.c_str()); 
    return f.is_open(); 
} 

string getFileName() 
{ 
    string filename; 
    cout << "Please enter in the name of the file you'd like to open: "; 
    cin >> filename; 
    return filename; 
} 

void getFile(string filename, /*out*/ ifstream& file) 
{ 
    const bool file_exists = checkFileExistence(filename); 
    if (!file_exists) { 
     cout << "File " << filename << " not found." << endl; 
     filename = getFileName(); // poor style to reset input parameter though 
     ofstream dummy(filename.c_str(); 
     if (!dummy.is_open()) { 
      cerr << "Could not create file." << endl; 
      return; 
     } 
     cout << "File created." << endl; 
    } 
    file.open(filename.c_str()); 
} 

int main() 
{ 
    // ... 
    ifstream file; 
    getFile("filename.ext", file); 
    if (file.is_open()) { 
     // do any stuff with file 
    } 
    // ... 
}
+0

Merci !!! après un peu de bricolage avec votre code, j'ai finalement eu ce que je voulais. : D – wrongusername

+1

Alors que ce fragment de code peut résoudre la question, [y compris une explication] (http://meta.stackexchange.com/questions/114762/explaining-entirely- code-based-answers) contribue vraiment à améliorer la qualité de votre message. Rappelez-vous que vous répondez à la question pour les lecteurs dans le futur, et que ces personnes pourraient ne pas connaître les raisons de votre suggestion de code. – NathanOliver

3

ifstream ne supporte pas la copie construire la sémantique (que ce que le message d'erreur SAIS essentiellement), de sorte que vous ne pouvez pas retourner un ifstream. Renvoyer un ifstream * à la place, et passer à l'appelant la responsabilité de supprimer le pointeur d'allocation.

+0

Ok ... Je mets en "retour & troisième" et maintenant il me prévient que "l'adresse de la variable locale" troisième "retourné." Que dois-je faire dans main() alors? – wrongusername

+0

ne jamais revenir & pile_variable. Allouer l'ifstream avec un nouvel opérateur et renvoyer le pointeur. –

+0

Vous voulez dire quelque chose comme "ifstream returnStream = &first; return returnStream;"? btw, ça ne marche pas non plus. cela me donne une erreur: "main.cpp: 56: erreur: conversion de 'std :: ifstream *' en type non-scalaire 'std :: ifstream' demandé principal.cpp: 57: erreur: conversion invalide de 'void *' à 'std :: ifstream *' " – wrongusername

14

Non, pas vraiment. ifstream n'a pas de constructeur de copie, et si vous essayez d'en retourner un, cela signifie copier l'instance de votre fonction là où le retour doit aller.

La solution de contournement habituelle consiste à transmettre une référence à un et à modifier cette référence dans votre fonction. Edit: alors que cela permettra à votre code de fonctionner, il ne résoudra pas le problème de base. À l'heure actuelle, vous mélangez deux responsabilités plutôt différentes en une seule fonction: 1) obtenir un nom de fichier, 2) ouvrir ou créer ce fichier. Je pense que si vous les séparez, le code sera plus simple, et il sera beaucoup plus facile d'éliminer la source du problème que vous voyez.

Édition 2: L'utilisation d'une référence comme celle-ci fonctionne parfaitement sans operator=. L'idée générale est quelque chose comme:

int open_file(char const *name, fstream &stream) { 
    stream.open(name); 
} 

L'opérateur d'affectation est ni nécessaire ni utile dans ce cas - nous utilisons simplement le fstream existant via la référence. Un operator= serait nécessaire si et seulement si nous devions passer l'argument au ctor. Avec un flux, nous pouvons par défaut construire un flux qui ne se connecte pas à un fichier, puis utiliser open pour se connecter au fichier après le fait.

+0

Merci, je l'ai fait, mais malheureusement, le code ne fonctionne toujours pas. database = * getFile(); "Je reçois une erreur sur cette ligne de" main.cpp: 29: note: méthode synthétisée 'std :: basic_ifstream > :: basic_ifstream (const std :: basic_ifstream > &) 'premier requis ici' – wrongusername

+0

mais je pense que cela m'a fait descendre à cette erreur, cependant – wrongusername

+0

Le "truc" de passer dans une référence pour éviter de retourner un nouvel objet sera seulement travailler pour les types qui ont un 'opéra tor = '. std :: ifstream n'a pas non plus cela, donc ce conseil ne marchera pas pour vous. – MSalters