C ++ RAII类中的OpenGL对象不再起作用 [英] OpenGL object in C++ RAII class no longer works

查看:95
本文介绍了C ++ RAII类中的OpenGL对象不再起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在C ++类中有一个OpenGL对象.由于我正在使用RAII,因此我希望析构函数将其删除.所以我的课看起来像这样:

I have an OpenGL object in a C++ class. Since I'm employing RAII, I want to have the destructor delete it. So my class looks something like:

class BufferObject
{
private:
  GLuint buff_;

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

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

//Other members.
};

这似乎可行.但是,无论何时执行以下任何操作,使用它时我都会开始遇到各种OpenGL错误:

This seems like it works. But any time I do any of the following, I start getting various OpenGL errors when I use it:

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.

这是怎么回事?

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

Note: this is an attempt to build a canonical answer to these questions.

推荐答案

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

All of those operations copy the C++ object. Since your class did not define a copy constructor, you get the compiler-generated copy constructor. This simply copies all of the members of the object.

考虑第一个示例:

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对象.

When you call push_back, it copies some_buffer into a BufferObject in the vector. So, right before we exit that scope, there are two BufferObject objects.

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

But what OpenGL buffer object do they store? Well, they store the same one. After all, to C++, we just copied an integer. So both C++ objects store the same integer value.

当我们退出该范围时,some_buffer将被销毁.因此,它将在此OpenGL对象上调用glDeleteBuffers.但是向量中的对象仍将具有其自己的OpenGL对象名副本.其中已被破坏.

When we exit that scope, some_buffer will be destroyed. Therefore, it will call glDeleteBuffers on this OpenGL object. But the object in the vector will still have its own copy of that OpenGL object name. Which has been destroyed.

所以您不能再使用它;因此是错误.

So you can't use it anymore; hence the errors.

InitBuffer函数也会发生相同的情况. buff复制到返回值后将被销毁,这使得返回的对象变得一文不值.

The same thing happens with your InitBuffer function. buff will be destroyed after it is copied into the return value, which makes the returned object worthless.

这都是由于违反了C ++中所谓的"3/5规则".您创建的析构函数没有创建复制/移动构造函数/赋值运算符.不好.

This is all due to a violation of the so-called "Rule of 3/5" in C++. You created a destructor without creating copy/move constructors/assignment operators. That's bad.

要解决此问题,您的OpenGL对象包装器应为仅移动类型.您应该删除复制构造函数和复制分配运算符,并提供将从其移动的对象设置为对象0的移动等效项:

To solve this, your OpenGL object wrappers should be move-only types. You should delete the copy constructor and copy assignment operator, and provide move equivalents that set the moved-from object to object 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包装器

There are various other techniques for making move-only RAII wrappers for OpenGL objects.

这篇关于C ++ RAII类中的OpenGL对象不再起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆