15

私は2つのリソース管理クラスを持っていますDeviceContextOpenGLContextはともにclass DisplayOpenGLのメンバです。リソースの寿命はDisplayOpenGLに固定されています。初期化は、この(擬似コード)のようになります。C++ - クラスメンバを初期化する前に関数を実行する

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; 
}; 
:私は DisplayOpenGL c'torの初期化子リストでそれを行うことはできませんので、

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

問題は、SetPixelFormat()の呼び出しです私が見ることができる

ソリューション:

  • m_dummy(m_device.SetPixelFormat())を挿入するには、 - (SetPixelFormatとして動作しません)何RETVALを持っていません。 (リトバルがあればこれを行うべきですか?)
  • OpenGLContext m_opengl;の代わりにunique_ptr<OpenGLContext> m_opengl;を使用してください。
    が続いm_opengl()として初期化し、c'tor本体にSetPixelFormat()を呼び出し、DeviceContext c'tor

これらのソリューションのが望ましいと理由からm_opengl.reset(new OpenGLContext);

  • コールSetPixelFormat()を使うのか?私が紛失しているものは何ですか?

    Windows上でVisual Studio 2010 Expressを使用しています(問題がある場合)。

    編集:私は主に、これらの方法のいずれかを決定する際のトレードオフに関心があります。私が代わりに「ノーマル」X m_xメンバーのそれを使用するとき -

    • m_dummy()はそれだろう
    • unique_ptr<X>は私に興味がある場合でも、仕事と洗練思わないのでしょうか? 2つのメソッドは、初期化の問題を除いて、機能的に多かれ少なかれ同等のようです。
    • SetPixelFormat()DeviceContextから呼び出すと確かに動作しますが、私には汚れているように感じます。 DeviceContextは、リソースを管理し、その使用を有効にする必要があります。ユーザーにランダムなピクセル形式のポリシーを適用する必要はありません。
    • stijn'sInitDev()は最もクリーンなソリューションのようです。

    とにかく、このような場合にスマートポインタベースのソリューションがほしいと思っていますか?

  • +0

    を呼び出すことも、初期化を行うにはOpenGLContextクラスのメソッドCreateRenderingContextを作成したいです。 – cdhowie

    +0

    あなたの3番目のソリューションがうまくいくように思えます。あなたが選んだ理由はありますか?また、GLFWのようなライブラリを使用してOpenGLコンテキストをロードしてみませんか? –

    +0

    私が始めた時、私はGLFWを知らなかった。見ていただき、ありがとうございます。 –

    答えて

    12

    Comma operator to the rescue!(a, b)は、a、次にbと評価されます。

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

    DeviceContextに属していれば(それはあなたのコードのようです)、DeviceContext c'torから呼び出してください。

    1

    両方の場合にuniqe_ptrを使用することは適切です:a good thingというヘッダーを含めるのではなく、DeviceContextとOpenGLContextを宣言することができます。

    class DisplayOpenGL 
    { 
    public: 
        DisplayOpenGL(HWND h); 
    private: 
        unique_ptr<DeviceContext> m_device; 
        unique_ptr<OpenGLContext> m_opengl; 
    }; 
    
    namespace 
    { 
        DeviceContext* InitDev(HWND h) 
        { 
        DeviceContext* p = new DeviceContext(h); 
        p->SetPixelFormat(); 
        return p; 
        } 
    } 
    
    DisplayOpenGL::DisplayOpenGL(HWND h): 
        m_device(InitDev(h)), 
        m_opengl(new OpenGLContext(*m_device)) 
    { 
    } 
    

    C++ 11を使用できる場合は、InitDev()をラムダに置き換えることができます。あなたは、オプションやメンバーの一人にしたいとき

    1

    OpenGLContextは0引数コンストラクタを持ち、コンストラクタをコピーする場合は、

    DisplayOpenGL(HWND hwnd) 
    : m_device(hwnd) 
    { 
        m_device.SetPixelFormat(); 
        m_opengl = OpenGLContext(m_device); 
    }; 
    

    unique_ptrにあなたのコンストラクタを変更することができますが、一般的に「NULL可能」を使用しているあなたがかもしれませんかここではしたくないかもしれません。

    3

    私はかなり常にとにかく、このような場合にスマートポインタベースのソリューションをしたいですか?

    いいえこの不要な合併症は避けてください。

    言及されていない二つの即時のアプローチ:

    アプローチA:

    きれいな方法。

    コンストラクタでSetPixelFormat()を呼び出すm_deviceのストレージ用の小さなコンテナオブジェクトを作成します。次に、DisplayOpenGL ::m_deviceをそのタイプのインスタンスに置き換えます。初期化の順序が得られ、その意図ははっきりしています。イラスト:

    class DisplayOpenGL { 
    public: 
        DisplayOpenGL(HWND hwnd) 
         : m_device(hwnd), 
          m_opengl(m_device) { } 
    private: 
        class t_DeviceContext { 
        public: 
         t_DeviceContext(HWND hwnd) : m_device(hwnd) { 
          this->m_device.SetPixelFormat(); 
         } 
         // ... 
        private: 
         DeviceContext m_device; 
        }; 
    private: 
        t_DeviceContext m_device; 
        OpenGLContext m_opengl; 
    }; 
    

    アプローチB:

    迅速&汚いやり方。この場合、静的関数を使用することができます。

    class DisplayOpenGL { 
    public: 
        DisplayOpenGL(HWND hwnd) 
        : m_device(hwnd), 
         m_opengl(InitializeDevice(m_device)) { } 
    private: 
        // document why it must happen this way here 
        static DeviceContext& InitializeDevice(DeviceContext& pDevice) { 
         pDevice.SetPixelFormat(); 
         return pDevice; 
        } 
    private: 
        DeviceContext m_device; 
        OpenGLContext m_opengl; 
    }; 
    
    1

    まず、間違っています。 :-)コンストラクタで複雑なことをするのは非常に貧しい習慣です。これまで代わりにコンストラクタに渡さなければならないヘルパーオブジェクトに対してこれらの操作を機能させます。あなたのクラスの外にあなたの複雑なオブジェクトを構築し、それらを他のクラスに渡す必要がある場合には完全に作成されたものを渡す方が良いでしょう。同時に、そのコンストラクタにも同様に行うことができます。プラスあなたは、賢明なロギングを追加するなどのエラーを検出する機会を持っているそのよう

    class OpenGLInitialization 
    { 
    public: 
        OpenGLInitialization(HWND hwnd) 
         : mDevice(hwnd) {} 
        void     SetPixelFormat (void)  { mDevice.SetPixelFormat(); } 
        DeviceContext const &GetDeviceContext(void) const { return mDevice; } 
    private: 
        DeviceContext mDevice; 
    };   
    
    class DisplayOpenGL 
    { 
    public: 
        DisplayOpenGL(OpenGLInitialization const &ogli) 
        : mOGLI(ogli), 
         mOpenGL(ogli.GetDeviceContext()) 
         {} 
    private: 
        OpenGLInitialization mOGLI; 
        OpenGLContext mOpenGL; 
    }; 
    
    0

    はあなただけでカンマ演算子で使用できない変数やその他の複雑なものを定義することができますIIFE (Immediately-Invoked Function Expression)、とComma operatorを組み合わせる:

    struct DisplayOpenGL { 
        DisplayOpenGL(HWND hwnd) 
         : m_device(hwnd) 
         , opengl(([&] { 
          m_device.SetPixelFormat(); 
         }(), m_device)) 
        DeviceContext m_device; 
        OpenGLContext m_opengl; 
    }; 
    
    0

    あなたのケースではコンマ演算子はかなりうまくいくはずですが、この問題はクラスの悪い計画の結果だと思います。私は、コンストラクタにオブジェクトの状態を初期化させ、依存関係(OpenGLレンダリングコンテキストなど)を初期化させないようにします。私はOpenGLContextのコンストラクタがOpenGLレンダリングコンテキストを初期化していると仮定しています。それは私がしないことです。代わりに、私は、これは、静的なファクトリ関数はコンストラクタよりも有用かもしれ例一種のように思えるSetPixelFormat

    class OpenGLContext { 
    public: 
        OpenGLContext(DeviceContext* deviceContext) : m_device(deviceContext) {} 
        void CreateRenderingContext() { 
         m_device->SetPixelFormat(); 
         // Create the rendering context here ... 
        } 
    private: 
        DeviceContext* m_device; 
    }; 
    
    ... 
    
    DisplayOpenGL(HWND hwnd) : m_device(hwnd), m_opengl(&m_device) { 
        m_opengl.CreateRenderingContext(); 
    } 
    
    関連する問題