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

问题描述

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

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

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

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

std::unique_ptr::reset()

我知道对象应该已经在构造函数的主体中初始化了,这里不是这种情况。我觉得我可能在 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(); } Renderer 之间做了一些反向依赖,或者我的总体架构是错误的。我宁愿依赖于基于作用域在正确时刻调用的构造函数和析构函数,而不是我手动触发它。

什么是更好的解决方案?

解决方法

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

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

  2. Window 派生您的 GLFWInit 类。

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