Search code examples
c++constructorinitializationsmart-pointersinitialization-list

C++ - Run a function before initializing a class member


I have 2 resource managing classes DeviceContext and OpenGLContext both are members of class DisplayOpenGL. The resource lifetimes are tied to DisplayOpenGL. Initialization looks like this (pseudo code):

DeviceContext m_device = DeviceContext(hwnd);
m_device.SetPixelFormat();
OpenGLContext m_opengl = OpenGLContext(m_device);

The problem is the call to SetPixelFormat(), since I can't do that in the initializer list of the DisplayOpenGL c'tor:

class DisplayOpenGL {
public:
    DisplayOpenGL(HWND hwnd)
    : m_device(hwnd),
      // <- Must call m_device.SetPixelFormat here ->
      m_opengl(m_device) { };
private:
    DeviceContext m_device;
    OpenGLContext m_opengl;
};

Solutions that I can see:

  • Inserting m_dummy(m_device.SetPixelFormat()) - Won't work as SetPixelFormat() has no retval. (should you do this if it had a retval?)
  • Use unique_ptr<OpenGLContext> m_opengl; instead of OpenGLContext m_opengl;.
    Then initialize as m_opengl(), call SetPixelFormat() in the c'tor body and use m_opengl.reset(new OpenGLContext);
  • Call SetPixelFormat() from DeviceContext c'tor

Which of these solutions is preferable and why? Anything I am missing?

I'm using Visual Studio 2010 Express on Windows, if it matters.

Edit: I'm mostly interested in the tradeoffs involved in deciding for one of these methods.

  • m_dummy() doesn't work and seems inelegant even if it would
  • unique_ptr<X> is interesting to me - when would I use it instead of a "normal" X m_x member? The two methods seem to be functionally more or less equivalent, except for the initialization issues.
  • Calling SetPixelFormat() from DeviceContext c'tor certainly works but feels unclean to me. DeviceContext should manage the resource and enable its use, not impose some random pixel format policy on users.
  • stijn's InitDev() looks like the cleanest solution.

Do I pretty much always want a smart pointer based solution in such cases anyway?


Solution

  • Comma operator to the rescue! An expression (a, b) will evaluate a first, then b.

    class DisplayOpenGL {
    public:
        DisplayOpenGL(HWND hwnd)
        : m_device(hwnd),
          m_opengl((m_device.SetPixelFormat(), m_device)) { };
    private:
        DeviceContext m_device;
        OpenGLContext m_opengl;
    };