在 C9803 中

在 C++ 98/03 中封裝 OpenGL 物件需要遵守 C++規則 3.這意味著新增複製建構函式,複製賦值運算子和解構函式。

但是,複製建構函式應該在邏輯上覆制該物件。複製 OpenGL 物件是一件非常重要的事情。同樣重要的是,它幾乎肯定是使用者不希望做的事情。

因此,我們將使物件不可複製:

class BufferObject
{
public:
    BufferObject(GLenum target, GLsizeiptr size, const void *data, GLenum usage)
    {
        glGenBuffers(1, &object_);
        glBindBuffer(target, object_);
        glBufferData(target, size, data, usage);
        glBindBuffer(target, 0);
    }
    
    ~BufferObject()
    {
        glDeleteBuffers(1, &object_);
    }
    
    //Accessors and manipulators
    void Bind(GLenum target) const {glBindBuffer(target, object_);}
    GLuint GetObject() const {return object_;}

private:
    GLuint object_;
    
    //Prototypes, but no implementation.
    BufferObject(const BufferObject &);
    BufferObject &operator=(const BufferObject &);
};

建構函式將建立物件並初始化緩衝區物件的資料。解構函式將破壞物件。通過宣告覆制建構函式/賦值而不定義它們,如果任何程式碼試圖呼叫它們,連結器將給出錯誤。通過宣稱它們是私有的,只有 BufferObject 的成員甚至可以呼叫他們。

請注意,BufferObject 不會保留傳遞給建構函式的 target。這是因為 OpenGL 緩衝區物件可以與任何目標一起使用,而不僅僅是最初建立的目標。這與紋理物件不同,紋理物件必須始終繫結到最初建立的目標。

因為 OpenGL 非常依賴於將物件繫結到上下文以用於各種目的,所以具有 RAII 樣式的範圍物件繫結通常也是有用的。因為不同的物件具有不同的繫結需求(一些具有目標,而另一些沒有),我們必須分別為每個物件實現一個。

class BindBuffer
{
public:
    BindBuffer(GLenum target, const BufferObject &buff) : target_(target)
    {
        buff.Bind(target_);
    }
    
    ~BindBuffer()
    {
        glBindBuffer(target_, 0);
    }
    
private:
    GLenum target_;

    //Also non-copyable.
    BindBuffer(const BindBuffer &);
    BindBuffer &operator=(const BindBuffer &);
};

BindBuffer 是不可複製的,因為複製它是沒有意義的。請注意,它不會保留對它所繫結的 BufferObject 的訪問許可權。那是因為沒必要。