2012-07-16 60 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類型的容器),這可能會對您不利。