I've written a RAII wrapper for C function pairs which initialize and release resources and it serves me well for most cases.
#include <GL/glfw.h>
#include <string>
#include <functional>
#include <stdexcept>
template <typename UninitFuncType,
typename SuccessValueType,
SuccessValueType successValue>
class RAIIWrapper
{
public:
template <typename InitFuncType, typename... Args>
RAIIWrapper(InitFuncType initializer,
UninitFuncType uninitializer,
const std::string &errorString,
const Args&... args) :
uninit_func(uninitializer)
{
if (successValue != initializer(args...))
throw std::runtime_error(errorString);
initialized = true;
}
bool isInitialized() const
{
return initalized;
}
~RAIIWrapper()
{
if (initalized)
uninit_func();
}
// non-copyable
RAIIWrapper(const RAIIWrapper &) = delete;
RAIIWrapper& operator=(const RAIIWrapper &) = delete;
private:
bool initalized = false;
std::function<UninitFuncType> uninit_func;
};
using GLFWSystem = RAIIWrapper<decltype(glfwTerminate), decltype(GL_TRUE), GL_TRUE>;
using GLFWWindow = RAIIWrapper<decltype(glfwCloseWindow), decltype(GL_TRUE), GL_TRUE>;
int main()
{
GLFWSystem glfw(glfwInit,
glfwTerminate,
"Failed to initialize GLFW");
}
However, say when a function returns void
like Enter/LeaveCriticalSection
I'm not sure how to go about and do it in this class. Should I specialize the class for SuccessValueType = void
case? Or something with default template parameter should do?
I'd like to note, that
You do not need information on your initialization function in your wrapper class. You only need to know about uninitialization function.
You can create function helpers to instantiate your wrapper.
I came up with the following solution (I liked @ipc exception handling idea)
Example:
Edit
RAII_wrapper_type
should have move semantics and we should carefully implement its move constructor to preventuninit_f
from calling several times.