c++ - C++ RAII 类中的 OpenGL 对象不再有效

标签 c++ c++11 opengl

我在 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.

发生了什么事?

注意:这是对这些问题建立规范答案的尝试。

最佳答案

所有这些操作都会复制 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 复制到 vector 中的 BufferObject 中。因此,就在我们退出该范围之前,有两个 BufferObject 对象。

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

当我们退出该范围时,some_buffer 将被销毁。因此,它将在这个 OpenGL 对象上调用 glDeleteBuffers。但是 vector 中的对象仍然有它自己的那个 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.
};

various other techniques用于为 OpenGL 对象制作只能移动的 RAII 包装器。

关于c++ - C++ RAII 类中的 OpenGL 对象不再有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46839586/

相关文章:

c++ - 遍历对列表,列表在数组中

c++ - 将 lambda 函数指定为默认参数

c++ - 强制或阻止使用特定次要版本的 libstdc++

c - OpenGL - 无法将超过一定大小的数据复制到绑定(bind) VBO

java - JOGL 如何搜索 OpenGL 库?

c++ - 使用 Qt 和 Opengl 强制注销崩溃

c++ - 获取 vector 的大小(以字节为单位)

c++ - gdb 关于符号的问题

c++ - qDebug() 不显示 const std::string&

c++ - 在发布序列中使用原子读-修改-写操作