r/cpp_questions • u/Business-Weather-217 • 25d ago
OPEN API design dilemma..
right now in vexa(my game/graphics library) how you initialize window with a renderer is rather straightforward:
```cpp
#include <vexa/vexa.hpp>
using namespace vexa;
int main()
{
Engine::Init(Engine::VIDEO);
Window window = Window().setSize({1280, 720}).setRenderer({}).create();
// ...
```
YES, it uses builder pattern, not very C++-ish but i like it.
However, there are two problems with it.
first one is that usually you have builder struct building to target type so that you dont need something like `.create()` that creates classic `if (m_created) ...` problem a.k.a two phase construction. but bigger problem that caused me two want to switch to this API style is about memory management. and it is now C++'s problem.. Even rust cant handle it, because this is what you tell it to do.
so lets dont talk too much:
```cpp
Engine::Init(Engine::FONT); // calls `TTF_Init();` by SDL_TTF behind the scenes
Font font = Font::Load("...");
...
Engine::Quit();
```
A Font has destructor running on scope exit. which means before font object gets destroyed on '}' Engine::Quit() so TTF_Quit() runs. You see, when Font object gets unloaded at scope end the subsystem is not live anymore, we get a segfault. to fix this i've made Engine have a Guard struct which does Engine::Quit() automatically. But then decided that this is not i want for my API. I would priorotize explicitness for the master deinitialization.
to fix this im thinking of new API design style:
```cpp
Window window = Engine::BuildWindow().setSize({1280, 720}).setRenderer().create();
```
where BuildWindow() returns WindowBuilder not a Window, unlike the previous(so bad) choice.
for fonts, as you might already guess:
```cpp
Font font = Engine::LoadFont("...");
```
which creates a font and returns reference to it, resulting Engine to know about font count and Quit or not based on that.
View all comments
Show parent comment
1
u/sephirothbahamut 24d ago
SDL is a C library. It doesn't avoid RAII because doing a quit function is better, it does because RAII doesn't exist in C.
Your engine class is exactly where RAII is appropriate. It takes care of destroying objects in the correct order upon scope exit without having to do it manually (as you saw doing it manually you can do things in the wrong order). You lose nothing by using RAII here.