Return ifstream to function

Here is probably a very noob question for you: how (if at all possible) can I return ifstream from a function?

Basically, I need to get the database file name from the user, and if the database with this name does not exist, then I need to create this file for the user. I know how to do this, but only asking the user to restart the program after creating the file. I wanted to avoid this inconvenience for the user, if possible, but the function below does not compile in 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: sorry, forgot to tell you where and what happened to the compiler:

 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: I changed the function to return a pointer instead, as Remus suggested, and changed the line in main () to "ifstream database = * getFile ()"; now I get this error again, but this time in the main () line:

 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 
+7
c ++ fstream ifstream ofstream
source share
5 answers
 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 } // ... } 
+5
source share

No, not at all. ifstream does not have a copy constructor, and if you try to return it, it means that copying the instance in your function goes where you need to return.

The usual workaround is to pass a link to one and change that link in your function.

Edit: while this allows your code to work, it will not fix the underlying problem. Right now you are mixing two quite different responsibilities into one function: 1) get the file name, 2) open or create this file. I think that if you separate them, the code will be simpler and much easier to eliminate the source of the problem you are seeing.

Editing 2: Using such a link works fine without operator= . The general idea is something like:

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

The assignment operator is neither necessary nor useful in this case - we just use the existing stream through the link. operator= would be needed if and only if we had to pass an argument to ctor. With a stream, we can by default create a stream that does not connect to the file, and then use open to connect to the file after the fact.

+14
source share

ifstream does not support the semantics of building a copy (this error message is mainly sais), so you cannot return ifstream. Instead, return ifstream * and pass the response to the caller to remove the highlight pointer.

+3
source share

This comment may not answer your question, I just want to ask Mr. @Corwin about his answer: just like his code, we have: getFileName block to request a file name, I think we should code like this ( this is just my opinion):

 void getFile(/*out*/ ifstream& file){ string filename = getFileName(); const bool file_exist = checkFileExistence(filename); if (!file_exist){ .... } .... } 

And in int main() I think:

 int main(){ ifstream file; getFile(file); if (file.is_open()){ //some stuff } } 

In doing so, you can get filename from user input on the console.

By the way, thanks to Mr. @Corwin for the code, it helps me a lot.

0
source share

As an option, ifstream can be extended and a custom constructor added to a new class.

I expanded it to create a test resource stream, encapsulating the search for test resources inside it.

 // test_utils.h class TestResourceStream : public std::ifstream { public: TestResourceStream(const char* file_path); }; 
 // test_utils.cpp namespace fs = std::filesystem; fs::path test_resource_path(const char* file_path) { fs::path path{std::string{"tests/resources/"} + file_path}; if (!fs::exists(path)) throw std::runtime_error{std::string{"path "} + fs::absolute(path).c_str() + " does not exist"}; return path; } TestResourceStream::TestResourceStream(const char* file_path) :std::ifstream{test_resource_path(file_path).c_str()} {} 
 // usage in test TEST_CASE("parse") { std::list<GosDump::Expertise> expertises; TestResourceStream stream("requests/page_response.json"); GosDump::Json::parse(expertises, stream); REQUIRE(10 == expertises.size()); } 
0
source share

All Articles