Search code examples
c++c++11fstream

Share a file between a thread and my main


I have a file that I want to declare in a main, but modify in a thread.

I declare in my MainWindow header file std::ofstream file; .

Then I try to initialize it my constructor of my MainWindow.cpp like this : file("test.txt", std::ios::out | std::ios::trunc);

The function in the thread is static:

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);

        // Constructs the new thread and runs it. Does not block execution.

        ref_bool_Server = true;
        fichier ("test.txt", std::ios::out | std::ios::trunc);
        m_t1 = std::thread(lancerServeur, std::ref(ref_bool_Server), std::ref(lancerEnregistrement));

        // Je sauvegarde ma main window
        m_psMainWindow = this;

    }

    MainWindow::~MainWindow()
    {
        delete ui;
        ref_bool_Server = false;
        m_t1.join();
    }


        void MainWindow::lancerServeur(std::atomic<bool>& boolServer, std::atomic<bool>& lancerEnregistrement){
            serveur s;//J'instancie un serveur
            StructureSupervision::T_StructureSupervision* bufferStructureRecu;
        while(boolServer){
            bufferStructureRecu = s.receiveDataUDP();
            if(bufferStructureRecu != NULL){
               m_psMainWindow->emit_signal_TrameRecu( bufferStructureRecu );
            }
            if(lancerEnregistrement){
                fichier << bufferStructureRecu->SystemData._statutGroundFlight;
            }
        }

    }

The de claration of the ofstream is false (probably synthaxic), and I don't know how to use this file in a static function.


Solution

  • Technically speaking, you can't call a constructor, at least not in the sense you mean. (An expression such as std::ofstream( "test.txt" ) looks like you're calling a constructor, but the standard calls it an explicit type conversion.) The constructor is called when you define a variable, e.g. in the statement std::ofstream file; (which calls the default constructor). When you write file(...), the compiler looks for an overloaded operator() in the type of file; there isn't one, so it is an error.

    It's not clear what you actually want to do, so it's difficult to provide exact advice. One thing is sure, however: you do not want a definition of a variable (e.g. std::ofstream file; at namespace scope) in a header. If you do, that header can only be included in one source, or you'll end up with multiple definitions. (Such a definition would be reasonable in a class definition in a header.) At best, you would want extern std::ofstream file; in the header, with the definition in one (and only one) of the source files which include that header; in the definition, you can provide arguments which would be used for construction. Except that I can't think of a context where it would make sense to have an std::ofstream at namespace scope.

    EDIT:

    From your update of the question, from the error message, it looks like file is a member variable. In that case, you provide any arguments to the constructor in the initializer list of the constructor:

    MainWindow::MainWindow()
        : file( "test.txt" )
    {
    }
    

    And of course, if it is a member, you cannot access it without having an instance of the class. Which is not normally the case in a static member function.

    EDIT:

    After your update: it's still not clear whether you want fichier to be a static member or not. Typically, there will be only one MainWindow object; do both users have access to it? (This would normally be the preferred solution.) If so, there's no problem making it non-static, and initializing it as above. Or you could pass a reference to it (the fichier member) directly to the thread. This is the solution I would prefer. Alternatively, you could declare it static. In that case, you would need to explicitly define it in one, and only one source file:

    std::ofstream MainWindow::fichier;
    

    And you would then open it in the constructor:

    fichier.open( "test.txt" );
    

    This could cause problems, however, if more than one instance of MainWindow gets constructed.

    Finally, from the code you show: only the thread actually uses the file, so it might be preferrable to declaring it as a local variable in the lancerServer function. There's no point in making it visible to several threads if only one is going to access it. If this is due to a simplification in your posted code, and it is used by several threads, then you'll need to add code to synchronize access.