2012-07-16 63 views
0

我有一个指针结构的数组,像这样:错误,动态分配对象到一个数组

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); 
     } 
    } 
} 

这里是程序的输出(所有我在主函数中要做的就是实例化对象)

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

'memcpy'中的'sizeof(Vector)* index'是错误的。您没有分配那么多'Vector's,所以您不能将那么多的内存复制到该位置 – 2012-07-16 00:43:47

+1

调试器知道。你有没有试过使用它? – 2012-07-16 00:44:37

+2

你的代码片段中有许多可疑的东西,但最终没有足够的信息让我们做任何事情,除了猜测。您需要使用调试器来识别问题,或者至少帮助您构建一个[最小测试用例](http://sscce.org)。 – 2012-07-16 00:45:20

回答

5

有谁知道是什么原因导致这种情况发生?

使用memcpy是错误的。任何参考文档都会告诉你。

第一个参数是一个指向目标的指针,它将元素放入terrian_vertices数组中:terrian_vertices + index

第二个参数是一个指向源的指针,它是pos

(如果你很好奇,目的而来的源之前的原因是因为它平行的赋值运算符:destination = source

第三个参数是数据的复制,量而你的情况只是会是sizeof(Vector):它只是一个Vector它需要复制,而不是index

误用memcpy就像代码很容易导致未定义的行为,这很幸运地表现为错误。

如果是这样,有没有更好的方式动态分配结构 - 不使用memcpy?

是的。不要自己管理内存:使用std::vector和正常的复制语义。

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的一个实例和Color之一。

+0

酷,这似乎是做到这一点!但是,我收到一个错误,说“class std :: vector >'没有成员名为'emplace_back'”。奇怪的是,当你键入句号时,该功能甚至会出现在对话框中。我会尝试push_back功能。 – Darestium 2012-07-16 02:43:03

+1

@Darestium如果您使用的是GCC或clang,则需要添加“-std = C++ 11”或“-std = C++ 0x”标志。 – 2012-07-16 02:44:24

+0

@ R.MartinhoFernades我正在使用MinGW。对不起,我对C++来说很新,你的意思是把它添加到链接器参数中? – Darestium 2012-07-16 03:17:28

0
Vector *pos = new Vector((GLfloat)x, 0.0f, (GLfloat)-y); 
memcpy(pos, terrian_vertices, sizeof(Vector) * index); 

你不能那样做。 new为那里的Vectorpos分配足够的内存。但是,您继续将sizeof(Vector) * index字节复制到该位置。由于int index = x + y * width;为0,所以最终结果为0字节。下一次是2 *宽度 * pos`成为无人地带。

请注意,您不应该使用memcpy复制复杂类型。它可能没有问题,只需要一点点复制就可以了,但是如果使用某些类型(即由于内部语义而无法位复制的类型,如RAII类型的容器),这可能会对您不利。