通过 std::vector.data() 指向 std::vector 元素的指针指向损坏的数据

Pointer to std::vector's elements through std::vector.data() points to corrupt data

ON-TOPIC 编辑: 这个问题是关于超出范围的 std::vector(在函数内部定义的),而是指向其第一个元素的指针通过 std::vector.data() 返回。尝试使用返回指针指向的数据最终会导致数据损坏,因为 std::vector 中的数据已经超出范围并被释放。例如:

...
type *ptr;
type* function1(){
     std::vector<type> vector;
     return vector.data();
}
ptr = function1();
// ptr points to corrupt data here
...

ON-TOPIC SOLUTION:下面写的“WAY A”是一个解决方案,但是一时重复了数据。另一件事是,例如:

...
std::vector<type> vect;
void function1(std::vector<type> &vector){
     // Add data to vector
}
// Use the data inside vector
type *ptr = vect.data();
...

老问题...

上下文中的上下文:我正在编写这个引擎,我在网格中存储位置、法线、顶点和索引数据class。我使用所需 OpenGL 类型的动态数组,就像这样:

class Mesh(){   
    ... 
    GLfloat *vertices;   
    GLubyte *indices;   
    ...
}

我用笔和纸设计了一个立方体,包括它的顶点、纹理坐标、法线和索引,然后用这些数据填充我的动态数组(手动复制,std::copy 它到动态数组在适当的内存分配后(使用 new btw)。这就像一个魅力。立方体用这样的东西完美呈现:

...
glEnableClientState(GL_VERTEX_ARRAY);    
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
... 
glVertexPointer(3, GL_FLOAT, 0, meshInst->pos_coords);    
glTexCoordPointer(2, GL_FLOAT, 0, meshInst->tex_coords);
...
glDrawElements(
        GL_TRIANGLES, (CORRECT index count), GL_UNSIGNED_BYTE,
        meshInst->indices
    );
...

上下文: 我为 Mesh 创建了另一个构造函数,而不是将数据从 GLfloat、GLubyte 等数组复制到新分配的内存中。( 就像一个魅力我可能会重复),它执行以下操作:
1)从文件加载数据(已经过彻底测试,可以正确导入)到std::vector<GLfloat> positionsstd::vector<GLubyte> inds,等等
2)我尝试了两种将数据传递到我的动态数组以由 OpenGL 呈现的方法,方法 A 和方法 B:


方式A:

std::copy(positions.begin(), positions.end(), vertices);
std::copy(inds.begin(), inds.end(), indices);

结果: 与第一个构造函数中的效果完全一样
数据打印:

P[72] = { 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1 }
I[36] = { 0, 1, 2, 3, 2, 1, 6, 4, 7, 5, 7, 4, 10, 8, 9, 11, 9, 8, 13, 12, 15, 14, 15, 12, 17, 16, 19, 18, 19, 16, 23, 20, 21, 22, 21, 20 }

方式 B:

vertices = positions.data();
indices = inds.data();

结果:未绘制任何内容
数据打印:

P[72] = { 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1 }
I[36] = { 0, 1, 2, 3, 2, 1, 6, 4, 7, 5, 7, 4, 10, 8, 9, 11, 9, 8, 13, 12, 15, 14, 15, 12, 17, 16, 19, 18, 19, 16, 23, 20, 21, 22, 21, 20 }

问题是……为什么? 在我看来,问题出在 OpenGL 内部,主要是因为“std::vector”是 "guaranteed to be stored in contiguous storage locations in the same order as represented by the vector" .如 http://www.cplusplus.com/reference/vector/vector/data/ 所述。另外,如果我比较 'vertices' 和 'indices' 指向的数据,它实际上是相同的。自己比较两种数据印刷品。它们都是在加载后立即使用存储长度和动态数组指针打印的。

非常感谢您的宝贵时间,请毫不留情地回复,我喜欢学习。 PS: 请原谅我的英语,这是我的第二语言。

可能您的 std::vector 超出了范围。由于 glVertexPointer 不会创建深层副本,而只是存储指针,因此您必须确保 original vector 仍然存在,当您想要从 is.

绘制时

推荐的解决方案:将数据传输到顶点缓冲区对象中,这样您就不必再处理此类问题,并且作为一个好处,您还可以获得更好的性能。