如何正确管理构造函数中的初始化?

How to correctly manage initialisation in constructor?

我正在用 C++ 围绕 GLFW 和 OpenGL 编写一个简单的包装器,作为练习。我有一个 class Window 和一个 class RendererWindow class 拥有一个 Renderer 成员。

Window 在其构造函数和 运行 主循环中设置 GLFW 上下文,并调用其 Renderer 成员进行绘制。 Renderer 在其构造函数中设置缓冲区,并执行 OpenGL 操作。

我遇到的问题是 OpenGL 调用 require 以获得可用的 OpenGL 上下文。如果我只是在调用 Window 的构造函数之前初始化 Renderer,那么 Renderer 的构造函数将在创建 GLFW 上下文之前被调用。

我所做的是将 unique_ptr 存储到 Window 中的 Renderer,然后在 Window 的构造函数中调用 std::make_unique<Renderer> .然后,在析构函数中,我在销毁 GLFW 上下文之前调用 std::unique_ptr::reset(),这样我就可以调用 OpenGL 来释放仍然有效的上下文。

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();
}
        

我知道对象应该已经在构造函数的主体中初始化,但这里不是这种情况。我觉得我可能在 RendererWindow 之间做了一些反向依赖,或者我的总体架构是错误的。我宁愿依赖于根据范围在正确的时刻调用构造函数和析构函数,而不是我手动触发它。

什么是更好的解决方案?

我建议您创建一个单独的 class,将其命名为 GLFWInit,它会执行 GLFW 初始化并在其析构函数中调用 glfwTerminate()。那么你有两个选择:

  1. 在您的 Window class 中嵌入类型 GLFWInit 的对象。尽早放置成员,但至少要在 m_renderer 成员之前。

  2. GLFWInit.

    中导出 Window class

这两种方法都确保 GLFW 在 m_renderer 之前初始化并在之后拆除。然后您甚至不必将渲染器设为指针,可以直接嵌入成员(如果可行的话)。