错误,动态地将对象分配给数组

时间:2012-07-16 00:41:36

标签: c++ dynamic dynamic-memory-allocation

我有一个指向结构数组的指针,如下所示:

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?

2 个答案:

答案 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);

你做不到。 newVectorpos点分配了足够的内存。但是,您可以继续将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>