向量push_back导致断言错误,但列表push_back工作

时间:2014-01-23 06:10:42

标签: c++ qt opengl

我正在使用为Visual Studio 2008编译的Qt5.1。

我正在尝试渲染具有多个纹理的对象。在我的原始代码中,我使用网格类来管理加载3D对象,这基于本教程:

http://ogldev.atspace.co.uk/www/tutorial22/tutorial22.html

网格类包含一个包含纹理的矢量。纹理从文件加载图像数据,并跟踪渲染自身所需的所有OpenGL状态管理。

当我尝试使用Qt向我的网格类向量容器中添加多个纹理时,我收到“调试断言失败:_BLOCK_TYPE_US_VALID(pHead-> nBlockUse)”错误。在向向量添加纹理时调用析构函数时会发生此错误,类似于此线程中描述的内容:

Destructor called on object when adding it to std::list

我是Qt的新手,我想知道在这种情况下处理纹理的最佳方法是什么。教程代码使用GLEW而不是Qt,我不得不从QOpenGLFunctions继承来管理OpenGL状态以渲染纹理(我的网格类也继承自QOpenGLFunctions)。看起来默认的复制构造函数正在执行纹理对象的浅表副本,这会删除由Qt管理的内存。但是,当我切换到使用列表容器进行纹理时,我没有得到断言错误。

以下是我的代码的简化,说明了我的问题:

#include <QOpenGLFunctions_3_3_Core>
#include <list>
#include <vector>

class Texture : protected QOpenGLFunctions_3_3_Core
{

public:
    Texture() 
    { 
    }

    ~Texture()
    {
        std::cout << "destructor" << std::endl;
    }
};

std::vector<Texture> textureList; //this causes the assertion failure
//std::list<Texture> textureList; //this works
void tester()
{

    for (int i = 0; i < 3; i++)
    {
        Texture Texture;
        textureList.push_back(Texture);
    }
}

int main()
{
    tester();

    //Qt application code
}

1 个答案:

答案 0 :(得分:0)

此问题来自vectorlist之间内部实施的差异。

首先,list是双向链接列表,因此list可以在没有原始元素副本的情况下增长。但vector是动态分配的数组。如果vector的容量已满,vector将分配具有更大大小(Array doubling)的新数组,并将旧数组中的元素复制到新数组。下面的代码段显示了断言发生的原因。 (也许)

#include <iostream>
#include <list>
#include <vector>

class Texture
{

public:
  Texture() 
  {   
    std::cout << "constructor" << std::endl;
  }   
  Texture(const Texture &t) 
  {   
    std::cout << "copy constructor" << std::endl;
  }   

  ~Texture()
  {   
    std::cout << "destructor" << std::endl;
  }   
};

std::vector<Texture> textureList;
//std::list<Texture> textureList;
void tester()
{
  for (int i = 0; i < 3; i++)
  {   
    //textureList.reserve(4);
    std::cout << "Loop\n";
    Texture texture;
    textureList.push_back(texture);
    std::cout << "Capacity: " << textureList.capacity() << "\n";
  }   
  std::cout << "End\n";
}

int main()
{
  std::cout << "main\n";
  tester();
  std::cout << "main end\n";
}

<强>结果

main
Loop
constructor
copy constructor
Capacity: 1
destructor
Loop
constructor
copy constructor
copy constructor
destructor
Capacity: 2
destructor
Loop
constructor
copy constructor
copy constructor
copy constructor
destructor
destructor
Capacity: 4
destructor
End
main end
destructor
destructor
destructor

每当矢量增长时,纹理实例都会被销毁。

如果您阻止此问题,请使用vector::reserve(请查看以上代码:textureList.reserve(4))。但我认为这个代码会出现另一个问题,所以我建议使用纹理指针而不是纹理实例来处理。