2010-03-08 13 views
7

Probablemente sea una pregunta muy simple para usted: ¿Cómo (si es posible) puedo devolver un ifstream desde una función?Devolución de ifstream en una función

Básicamente, necesito obtener el nombre de archivo de una base de datos del usuario, y si la base de datos con ese nombre de archivo no existe, entonces necesito crear ese archivo para el usuario. Sé cómo hacerlo, pero solo al pedirle al usuario que reinicie el programa después de crear el archivo. Quería evitar ese inconveniente para el usuario, si es posible, pero la función de abajo no se compila en 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: Lo siento, se olvidó de decir dónde y cuál fue el error del compilador:

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 

EDITAR: Cambié la función para devolver un puntero en lugar de lo sugerido por Remus, y cambié la línea en main() a "ifstream database = * getFile()"; Ahora me sale este error de nuevo, pero esta vez en la línea en main():

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

Lo que has enumerado no es un error del compilador, es una "nota". Mira el error real. –

Respuesta

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

¡Gracias! después de un poco de retoques con tu código, finalmente obtuve lo que quería. : D – wrongusername

+1

Si bien este fragmento de código puede resolver la pregunta, [incluyendo una explicación] (http://meta.stackexchange.com/questions/114762/explaining-entirely-coded-based-answers) realmente ayuda a mejorar la calidad de tu publicación Recuerde que usted está respondiendo la pregunta a los lectores en el futuro, y es posible que esas personas no sepan los motivos de su sugerencia de código. – NathanOliver

3

ifstream no apoya copia construir semántica (que lo que el mensaje de error sais básicamente), por lo que no puede devolver un ifstream. Devuelva un ifstream * en su lugar, y pase a la persona que llama la responsabilidad de eliminar el puntero de asignación.

+0

Bien ... Puse "return & third" y ahora me advierte que "devolvió la dirección de la variable local 'third'". ¿Qué hago en main()? – wrongusername

+0

nunca regresa y stack_variable. Asigne el ifstream con el nuevo operador y devuelva el puntero. –

+0

¿Quiere decir algo como "ifstream returnStream = &first; return returnStream;"? por cierto, eso tampoco funciona. me da un error: "main.cpp: 56: error: conversión de 'std :: ifstream *' a tipo no escalar 'std :: ifstream' solicitado main.cpp: 57: error: conversión no válida de 'void *' a 'std :: ifstream *' " – wrongusername

14

No, realmente no. ifstream no tiene un constructor de copia, y si intentas devolver uno, eso significa copiar la instancia en tu función a donde sea que la devolución deba ir.

La solución habitual es pasar una referencia a uno y modificar esa referencia en su función.

Editar: mientras que eso permitirá que su código funcione, no solucionará el problema básico. En este momento, está mezclando dos responsabilidades bastante diferentes en una sola función: 1) obtener un nombre de archivo, 2) abrir o crear ese archivo. Creo que si los separa, el código será más simple y hará que sea mucho más fácil eliminar la fuente del problema que está viendo.

Editar 2: El uso de una referencia como esta funciona perfectamente bien sin un operator=. La idea general es algo así como:

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

El operador de asignación no es ni necesaria ni útil en este caso - simplemente usamos el fstream existente a través de la referencia. Un operator= sería necesario si y solo si tuviéramos que pasar el argumento a la ctor. Con una secuencia, podemos construir de forma predeterminada una secuencia que no se conecta a un archivo, y luego usar abrir para conectarnos al archivo después del hecho.

+0

¡Gracias! Lo hice, pero desafortunadamente el código aún no funciona. Usando "ifstream" database = * getFile(); "Aparece un error en esa línea de" main.cpp: 29: nota: método sintetizado 'std :: basic_ifstream > :: basic_ifstream (const std :: basic_ifstream > &) 'primero se requiere aquí " – wrongusername

+0

pero creo que me llevó a ese error. – wrongusername

+0

El" truco "de pasar una referencia para evitar devolver un nuevo objeto solo trabajar para tipos que tienen una 'opera tor = '. std :: ifstream tampoco tiene eso, por lo que este consejo no funcionará para usted. – MSalters

Cuestiones relacionadas