2017-10-19 8 views
7

私はOpenGLオブジェクトをC++クラスに持っています。私はRAIIを採用しているので、デストラクタにそれを削除させたい。ですから、私のクラスは次のようになります:C++ RAIIクラスのOpenGLオブジェクトは動作しなくなった

class BufferObject 
{ 
private: 
    GLuint buff_; 

public: 
    BufferObject() 
    { 
    glGenBuffers(1, &buff_); 
    } 

    ~BufferObject() 
    { 
    glDeleteBuffers(1, &buff_); 
    } 

//Other members. 
}; 

これは動作しているようです。しかし、私が次のいずれかを行うときは、いつでもさまざまなOpenGLエラーが出ます:

vector<BufferObject> bufVec; 
{ 
    BufferObject some_buffer; 
    //Initialize some_buffer; 
    bufVec.push_back(some_buffer); 
} 
bufVec.back(); //buffer doesn't work. 

BufferObject InitBuffer() 
{ 
    BufferObject buff; 
    //Do stuff with `buff` 
    return buff; 
} 

auto buff = InitBuffer(); //Returned buffer doesn't work. 

何が起こっているのですか?

注:これは、これらの質問に対する正式な回答を作成するための試みです。

答えて

9

これらの操作はすべて、C++オブジェクトをコピーします。あなたのクラスはコピーコンストラクタを定義していないので、コンパイラ生成コピーコンストラクタを取得します。これは、単にオブジェクトのすべてのメンバーをコピーします。あなたがpush_backを呼び出すとき、それはコピーvectorBufferObjectsome_buffer

vector<BufferObject> bufVec; 
{ 
    BufferObject some_buffer; 
    //Initialize some_buffer; 
    bufVec.push_back(some_buffer); 
} 
bufVec.back(); //buffer doesn't work. 

は、第一の例を考えてみましょう。したがって、そのスコープを終了する直前に、オブジェクトが2つあります(BufferObject)。

しかし、どのOpenGLバッファオブジェクトに格納されますか?さて、彼らはと同じものをに保存します。結局のところ、C++では整数をコピーしたばかりです。したがって、両方のC++オブジェクトは同じ整数値を格納します。

このスコープを終了すると、some_bufferが破棄されます。したがって、このOpenGLオブジェクトでglDeleteBuffersを呼び出します。しかし、ベクター内のオブジェクトは、そのOpenGLオブジェクト名の独自のコピーを保持します。どちらが破壊されました

もう使用できません。したがって、エラー。

InitBufferと同じことが起こります。 buffは戻り値にコピーされた後に破棄され、返されたオブジェクトは無価値になります。

これは、C++のいわゆる「3/5のルール」に違反しているためです。コピー/移動コンストラクタ/代入演算子を作成せずにデストラクタを作成しました。それは良くないね。

これを解決するには、OpenGLオブジェクトラッパーを移動専用のタイプにする必要があります。あなたはコピーコンストラクタを削除し、代入演算子をコピーして、設定された移動同等物を提供する必要があります移動-からオブジェクト0のオブジェクトへ:

class BufferObject 
{ 
private: 
    GLuint buff_; 

public: 
    BufferObject() 
    { 
    glGenBuffers(1, &buff_); 
    } 

    BufferObject(const BufferObject &) = delete; 
    BufferObject &operator=(const BufferObject &) = delete; 

    BufferObject(BufferObject &&other) : buff_(other.buff_) 
    { 
    other.buff_ = 0; 
    } 

    BufferObject &operator=(BufferObject &&other) 
    { 
    //ALWAYS check for self-assignment 
    if(this != &other) 
    { 
     Release(); 
     buff_ = other.buff_; 
     other.buff_ = 0; 
    } 

    return *this; 
    } 

    ~BufferObject() {Release();} 

    void Release(); 
    { 
    if(buff_) 
     glDeleteBuffers(1, &buff_); 
    } 

//Other members. 
}; 

は、OpenGLオブジェクトの移動のみRAIIラッパーを作るためvarious other techniquesがあります。

関連する問題