Frage

Hier ist wahrscheinlich eine sehr noobish Frage an Dich: Wie (wenn möglich) kann ich eine ifstream aus einer Funktion zurückgeben

Im Grunde genommen, ich brauche den Dateinamen eine Datenbank von dem Benutzer zu erhalten, und wenn die Datenbank mit diesem Dateinamen nicht existiert, dann muß ich diese Datei für den Benutzer erstellen. Ich weiß, wie das zu tun, sondern nur durch den Benutzer auffordert, das Programm nach dem Erstellen der Datei neu zu starten. Ich wollte, dass die Unannehmlichkeiten für den Benutzer, wenn möglich, vermeiden, aber die Funktion unten kompiliert nicht 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, vergessen, Ihnen zu sagen, wo und was der Compiler Fehler war:

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: Ich habe die Funktion geändert, um einen Zeiger zurück, anstatt wie Remus vorgeschlagen, und änderte die Linie in main () zu "ifstream Datenbank = * getFile ()"; Ich bekomme jetzt diesen Fehler wieder, diesmal aber in der Linie in 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
War es hilfreich?

Lösung

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
    }
    // ...
}

Andere Tipps

Nein, nicht wirklich. ifstream keine Kopie Konstruktor hat, und wenn Sie versuchen, eine zurückzukehren, das heißt die Instanz in Ihrer Funktion, um überall dort, wo die Rückkehr Bedürfnisse Kopieren zu gehen.

Die übliche Abhilfe ist in einem Verweis auf eine zu übergeben und modifizieren, dass die Bezugnahme in Ihrer Funktion.

Edit: während, dass der Code zur Arbeit ermöglichen wird, wird es nicht das grundlegende Problem beheben. Gerade jetzt, Sie mischen zwei ziemlich unterschiedliche Verantwortlichkeiten in eine einzige Funktion: 1) erhalten Sie einen Dateinamen, 2) öffnen oder die Datei erstellen. Ich denke, wenn man diejenigen trennen, wird der Code einfacher, und machen es viel einfacher, die Ursache des Problems Sie sehen, zu beseitigen.

Edit 2: eine Referenz wie diese Verwendung funktioniert sehr gut ohne operator=. Die allgemeine Idee ist so etwas wie:

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

Der Zuweisungsoperator ist weder notwendig noch sinnvoll in diesem Fall - wir einfach die vorhandene fstream über die Referenz. Ein operator= wäre notwendig, , wenn und nur wenn Wir hatten das Argument an die Ctor zu übergeben. Mit einem Strom können wir ein Stream Standard konstruieren, die nicht auf eine Datei nicht anschließen, und öffnen Sie dann verwenden, um die Datei nach der Tat zu verbinden.

ifstream nicht Kopie Konstrukt Semantik unterstützen (das, was die Fehlermeldung im Grunde sais), so dass Sie nicht eine ifstream zurückkehren können. Liefert ein ifstream * statt, und übergeben Sie den Anrufer die Verantwortung löschen der Zeiger zuweisen.

Dieser Kommentar kann Ihre Frage nicht beantworten, ich will nur Herren @Corwin über seine Antwort fragen: Genau wie sein Code, die wir haben: getFileName Block Dateinamen für Ihr Interesse, ich denke, wir sollten Code wie folgt (Dies ist meiner Meinung nach nur):

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

Und in int main(), denke ich:

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

Mit diesem können Sie filename von Benutzereingaben an der Konsole erhalten.

Durch die Art und Weise, danken Herrn @Corwin für den Code seiner Hilfe mir viel.

Als Option ifstream erweitert und benutzerdefiniertes Konstruktor werden kann, um neue Klasse hinzugefügt.

Ich habe es erweitert Testressourcenstrom zu erzeugen, Testressourcensuche in der es eingekapselt wird.

// 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());
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top