Search code examples
c++openglglfwabstractionglew

How to correctly manage initialisation in constructor?


I'm writing a simple wrapper in C++ around GLFW and OpenGL, as an exercice. I have a class Window and a class Renderer. The Window class owns a Renderer member.

Window sets the GLFW context in its constructor and run the main loop, and call for its Renderer member to draw. Renderer sets the buffers in its constructor, and does the OpenGL things.

The problem I've got is that OpenGL calls require to have an OpenGL context available. If I were to just initialise the Renderer before calling the constructor of Window, the constructor of Renderer would be called before the GLFW context would be created.

What I did is that I instead store a unique_ptr to a Renderer in Window, and I call std::make_unique<Renderer> in the constructor of Window. Then, in the destructor, I call std::unique_ptr::reset() before destroying the GLFW context, so that I can make the OpenGL calls to free stuff with a still valid context.

class Window
{
   public:
       Window()
       {
           //initialising GLFW and creating an OpenGL context
           //...
           m_renderer = std::make_unique<Renderer>();
       }
       ~Window()
       {
           m_renderer.reset();
           glfwTerminate();
       }
       int run()
       {
           while(...)
           {
               m_renderer->draw();
               //...
           }
           return 0;
       }
   private:
       std::unique_ptr<Renderer> m_renderer; 
       //...
}

class Renderer
{
    public:
        Renderer() { //Set buffers }
        ~Renderer() { //Free buffers }
        draw() { glDrawElements(...); //... }
    private:
        //...
}

int main()
{
     Window window();
     return window->run();
}
        

I understand that object should already be initialised in the body of the constructor, which is not the case here. I feel I might have done some dependency between Renderer and Window backwards or that my general architecture is wrong. I would rather rely on the constructor and destructors being called at the right moment based on the scope and not on me manually triggering it.

What would be a better solution?


Solution

  • I suggest that you create a separate class, call it GLFWInit that does the GLFW initialization and calls glfwTerminate() in its destructor. Then you have two options:

    1. Embed an object of type GLFWInit in your Window class. Place the member early, but at the least before the m_renderer member.

    2. Derive your Window class from GLFWInit.

    Both methods ensure that GLFW is initialied before m_renderer and torn down after it. Then you do not even have to make the renderer a pointer and can embed the member directly (if that is feasible).