1

我目前正在尝试使用glfw在 C++ 中编写一个小型引擎来创建窗口。我想充分利用 raii 来提出一个异常安全的架构,并使引擎几乎不可能以错误的方式使用。但我目前正在努力解决一些问题,我觉得我错过了一些重要的东西,所以我在这里问,提前谢谢大家!

假设我有一个raii名为的基本结构,它在和中glfw_context调用。它也接受一个并在调用之前设置它,但我会省略这些细节,因为我想专注于基本问题。我还创建了一个类,它需要 a在wheras 中采用相同类型的参数但带有 a is的重载。glfwInit()ctorglfwTerminate()dtorerror-callbackglfwInit()glfw_windowconst glfw_context&ctorctorglfw_context&&deleted

这背后的想法是,当上下文是时,rvalue它只会在ctor调用期间存在,但glfwTerminate()会在所有窗口被正确销毁之前被调用(这发生在dtor类中glfw_window)。我moves正确实现了,glfw_windowglfw_context不能复制或移动。但问题从这里开始:我无法阻止用户创建多个glfw_context实例。所以我static现在和一个成员一起去了,因为glfw没有公开像glfwIsInit()这样的东西,它在我的框架范围内解决了这个问题(只有最旧的实例会调用glfwTerminate()),但这仍然不能保护用户免于编写这样的代码:

std::vector< glfw_window > windows;
{
    // introduce explicit scope to demonstrate the problem
    glfw_context context{};
    windows.emplace_back( context, ... );
}

在这种情况下,上下文仍然不会超过窗口。

有解决这个问题的好方法吗?我不想把它作为要求放在文档中(像“上下文必须比每个窗口都活得久”之类的东西似乎对我来说并不适用)。

我目前的方法是使用 astd::shared_pointer< glfw_context >作为glfw_window's的参数ctor并将其存储为成员。但是,这仍然不能解决我的问题,因为我仍然可以make_shared< glfw_context >()使用不同的上下文并将它们传递给不同的窗口。并且由于只有第一个分配的实例会调用glfwTerminate()我仍然可以引发上下文在所有窗口之前被破坏的情况。

那么解决这类问题的正确方法是什么?无论用户如何尝试(错误)使用它,我能否构建一个在这里正常工作的漂亮架构?我的其他一些想法包括一个private ctoringlfw_context和一个static工厂方法与 - 方法相结合,shared_pointer但这感觉很像一个singleton,我怀疑这是处理事情的最佳方式。

4

1 回答 1

2

您可能会使用单例的变体:

class glfw_context
{
    glfw_context() {/*Your impl*/}

    glfw_context(const glfw_context&) = delete;
    glfw_context& operator=(const glfw_context&) = delete;
public:
    friend std::shared_ptr<glfw_context> CreateContext()
    {
        static std::weak_ptr<glfw_context> instance;

        auto res = instance.lock();
        if (res == nullptr) {
            res = std::make_shared<glfw_context>();
            instance = res;
        }
        return res;
    }

    /* Your impl */
};

然后,只要您的实例至少有一个“引用”,就CreateContext()返回它,否则它会创建一个新的。
不可能有 2 个不同的实例glfw_context

于 2018-01-26T13:15:19.700 回答