I'm writing a C++17 GUI library that uses two phase initialization. It sits on top of native GUI API (at present: Win32) and hides its complexity from the user.
Mapping Windows to C++ classes commonly requires two phase initialization: first phase creates C++ object and second phase creates API object.
This is required because the first opportunity to subscribe to window events is inside the constructor. Hence if your base constructor would already create window before you subscribe to events you would miss some. In addition to that one shouldn't call virtual functions from constructors in C++, so there's just no way around it.
I'd like to use the following pattern, to assure two phase initialization of a Windows resource (Window, GDI handles, etc.):
All functions that use resources have create() and destroy() member functions, derived from base template class.
template <class T>
class resource {
public:
virtual T* create()=0;
virtual void destroy()=0;
}
I can then derive classes from this:
class wnd : resource<wnd> {
// do the magic
}
To create these classes I would like to create a global library function that does something like this:
template <class T, typename... A>
// TODO: Need a concept here, but not available yet.
static std::unique_ptr<T> create(A... args)
{
T* ptr = new T(args...);
ptr->create();
return std::unique_ptr<T>(ptr);
}
So I'd call it like auto button=::create<button>(ctor args) and it would in turn pass arguments to ctor, return unique_ptr to my button and call create function on it.
Now I would like to implement destruction too. It would be attached to unique_ptr as custom deleter and would call destroy(). This is how I -in theory- think it should work.
// --- two phase construction pattern ---
template <typename T>
struct destroy {
void operator()(T* p) { p->destroy(); delete p; }
};
template <class T, typename... A>
static std::unique_ptr<T> create(A... args)
{
T* ptr = new T(args...);
ptr->create();
return std::unique_ptr<T, destroy<T>>(ptr);
}
The problem is that this fails because std::unique_ptr<T, destroy> is not convertible to std::unique_ptr<T,std::default_delete). Since a lot of functions accept std::unique_ptr derivates, I can't add another template parameter to all of them, it would complicate things for the library user.
I thought about calling destroy in destructors, but then I read that constructors and destructors should avoid calling virtual functions so I'd have to re-implement this in every destructor. Library user might forget this in derived class and create a memory leak.
Is there a nicer solution for this problem?