Returning ifstream in a function

后端 未结 4 2140
日久生厌
日久生厌 2021-02-13 11:13

Here\'s probably a very noobish question for you: How (if at all possible) can I return an ifstream from a function?

Basically, I need to obtain the filename of a databa

相关标签:
4条回答
  • 2021-02-13 11:38

    ifstream does not support copy construct semantics (that what the error message basically sais), so you cannot return an ifstream. Return an ifstream* instead, and pass to the caller the responsability to delete the allocate pointer.

    0 讨论(0)
  • 2021-02-13 11:38

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

    I've extended it to create test resource stream, encapsulating test resource lookup inside of 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 讨论(0)
  • 2021-02-13 11:44
    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 讨论(0)
  • 2021-02-13 11:47

    No, not really. ifstream doesn't have a copy constructor, and if you try to return one, that means copying the instance in your function out to wherever the return needs to go.

    The usual workaround is to pass in a reference to one, and modify that reference in your function.

    Edit: while that will allow your code to work, it won't fix the basic problem. Right now, you're mixing two rather different responsibilities into a single function: 1) obtain a file name, 2) open or create that file. I think if you separate those, the code will be simpler, and make it much easier to eliminate the source of the problem you're seeing.

    Edit 2: Using a reference like this works perfectly well without an 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 simply use the existing fstream via the reference. An operator= would be necessary if and only if we had to pass the argument to the ctor. With a stream, we can default construct a stream that doesn't connect to a file, and then use open to connect to the file after the fact.

    0 讨论(0)
提交回复
热议问题