为了账号安全,请及时绑定邮箱和手机立即绑定

C ++ RAII类中的OpenGL对象不再起作用

C ++ RAII类中的OpenGL对象不再起作用

C++
凤凰求蛊 2019-11-20 09:39:34
我在C ++类中有一个OpenGL对象。由于我正在使用RAII,因此我希望析构函数将其删除。所以我的课看起来像这样: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.这是怎么回事?注意:这是为这些问题建立规范答案的尝试。
查看完整描述

3 回答

?
侃侃尔雅

TA贡献1801条经验 获得超16个赞

所有这些操作都复制C ++对象。由于您的类未定义副本构造函数,因此您将获得编译器生成的副本构造函数。这只是复制对象的所有成员。


考虑第一个示例:


vector<BufferObject> bufVec;

{

  BufferObject some_buffer;

  //Initialize some_buffer;

  bufVec.push_back(some_buffer);

}

bufVec.back(); //buffer doesn't work.

当你调用push_back,它复制some_buffer到一个BufferObject在vector。因此,在退出该范围之前,有两个BufferObject对象。


但是它们存储什么OpenGL缓冲区对象?好吧,它们存储相同的一个。毕竟,对于C ++,我们只是复制了一个整数。因此,两个C ++对象都存储相同的整数值。


当我们退出该范围时,some_buffer将被销毁。因此,它将调用glDeleteBuffers此OpenGL对象。但是向量中的对象仍将具有其自己的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包装。


查看完整回答
反对 回复 2019-11-20
  • 3 回答
  • 0 关注
  • 451 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信