我有一个指向结构数组的指针,如下所示:
class Terrian {
...
private:
Vector *terrian_vertices;
...
}
指针的数据在“construct_vertices”函数
中生成Terrian::Terrian(int width, int height) {
this->width = width;
this->height = height;
std::cout << "Width: " << width << " Height: " << height << "\n";
std::cout << "Vertices\n";
construct_vertices();
std::cout << "Element\n";
construct_elements();
std::cout << "Buffers\n";
construct_buffers();
}
void Terrian::construct_vertices() {
terrian_vertices = new Vector[width * height];
std::cout << "Generating data\n";
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
int index = x + y * width;
Vector *pos = new Vector((GLfloat)x, 0.0f, (GLfloat)-y);
memcpy(pos, terrian_vertices, sizeof(Vector) * index);
std::cout << terrian_vertices[index].x;
Color *color = new Color(0, 255, 0);
memcpy(color, terrian_colors, sizeof(Color) * index);
}
}
}
这是程序的输出(我在main函数中做的只是实例化对象)
Width: 32 Height: 32
Vertices
Generating data
5.2349e-039
Process returned -1073741819 (0xC0000005) execution time : 10.073 s
Press any key to continue.
当第一个指针被复制到数组时程序崩溃,'x'的输出应为0.这令人费解。有谁知道造成这种情况的原因是什么?如果是这样,有没有更好的方法动态分配结构 - 不使用memcpy?
答案 0 :(得分:5)
有谁知道造成这种情况的原因是什么?
memcpy
的使用不正确。任何参考文档都会告诉你。
第一个参数是指向目标的指针,它是index
数组中的terrian_vertices
个元素:terrian_vertices + index
。
第二个参数是指向源的指针,即pos
。
(如果你很好奇,目的地在源之前的原因是因为它与赋值运算符平行:destination = source
)
第三个参数是要复制的数据量,在您的情况下只是sizeof(Vector)
:它只需要一个 Vector
,而不是{{ 1}}。
像代码一样滥用index
很容易导致未定义的行为,这很幸运地表现为错误。
如果是这样,有没有更好的方法动态分配结构 - 不使用memcpy?
是。不要自己管理内存:使用std::vector
和普通的复制语义。
memcpy
注意现在看不到class Terrian {
// ...
private:
std::vector<Vector> terrain_vertices;
// Hmm, this may need some touch up on naming,
// or it may get confusing with two "vector" thingies around
};
// ...
void Terrian::construct_vertices() {
terrain_vertices.reserve(width * height);
// reserve is actually optional,
// but I put it here to parallel the original code
// and because it may avoid unneeded allocations
std::cout << "Generating data\n";
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
terrain_vertices.emplace_back((GLfloat)x, 0.0f, (GLfloat)-y);
// or this if your compiler doesn't support C++11:
// terrain_vertices.push_back(Vector((GLfloat)x, 0.0f, (GLfloat)-y));
std::cout << terrian_vertices[index].x;
// same thing for colors
terrain_colors.emplace_back(0, 255, 0);
}
}
的任何地方。这解决了原始代码的另一个问题:它在每个循环迭代中泄漏了一个new
实例和一个Vector
。
答案 1 :(得分:0)
Vector *pos = new Vector((GLfloat)x, 0.0f, (GLfloat)-y);
memcpy(pos, terrian_vertices, sizeof(Vector) * index);
你做不到。 new
为Vector
和pos
点分配了足够的内存。但是,您可以继续将sizeof(Vector) * index
个字节复制到该位置。第一次这个结果是0字节,因为int index = x + y * width;
是0.下次它是2 *宽度, which is likely greater than
1 , so you end up copying past
* pos`到无人的土地。
另外,您不应该使用memcpy
复制复杂类型。它可能是正常的,并且可能只需要一点点复制,但如果与某些类型一起使用(即由于内部语义而无法进行位复制的类型,如RAII样式容器),这可能对您有害。 / p>