2012-07-22 132 views
1

我有一個關於堆棧溢出錯誤的前一個問題,並切換到我的對象數組向量。如果需要,可以在這裏引用這個問題:How to get rid of stack overflow error如何加快向量初始化C++

但是我現在的問題是如何加速向量的初始化。我目前的方法目前需要〜15秒。使用數組而不是向量它需要第二個數組的大小足夠小的數組,而不會引發堆棧溢出錯誤。

這是怎麼了初始化它:

在main.cpp中我初始化我的地牢對象:

dungeon = Dungeon(0, &textureHandler, MIN_X, MAX_Y); 

在我的地牢(...)構造,我初始化房間的我5x5的矢量並調用loadDungeon:

Dungeon::Dungeon(int dungeonID, TextureHandler* textureHandler, int topLeftX, int topLeftY) 
{ 
    currentRoomRow = 0; 
    currentRoomCol = 0; 
    for (int r = 0; r < MAX_RM_ROWS; ++r) 
    { 
     rooms.push_back(vector<Room>()); 
     for (int c = 0; c < MAX_RM_COLS; ++c) 
     { 
      rooms[r].push_back(Room()); 
     } 
    } 
    loadDungeon(dungeonID, textureHandler, topLeftX, topLeftY); 
} 

我的房間構造填充細胞(這樣我就可以設置它們在loadDungeon功能)我30×矢量:

Room::Room() 
{ 
    for (int r = 0; r < MAX_ROWS; ++r) 
    { 
     cells.push_back(vector<Cell>()); 
     for (int c = 0; c < MAX_COLS; ++c) 
     { 
      cells[r].push_back(Cell()); 
     } 
    } 
} 

我的默認構造細胞簡單,沒有做太多,但無論如何,我會張貼:

Cell::Cell() 
{ 
    x = 0; 
    y = 0; 
    width = 16; 
    height = 16; 
    solid = false; 
    texCoords.push_back(0); 
    texCoords.push_back(0); 
    texCoords.push_back(1); 
    texCoords.push_back(0); 
    texCoords.push_back(1); 
    texCoords.push_back(1); 
    texCoords.push_back(0); 
    texCoords.push_back(1); 
} 

而且最後我loadDungeon()函數將設置細胞。最終這將從一個文件中讀取並加載單元格,但現在我想盡可能優化這一點。

void Dungeon::loadDungeon(int dungeonID, TextureHandler* textureHandler, int topLeftX, int topLeftY) 
{ 
    int startX = topLeftX + (textureHandler->getSpriteWidth()/2); 
    int startY = topLeftY - (textureHandler->getSpriteHeight()/2); 
    int xOffset = 0; 
    int yOffset = 0; 
    for (int r = 0; r < MAX_RM_ROWS; ++r) 
    { 
     for (int c = 0; c < MAX_RM_COLS; ++c) 
     { 
      for (int cellRow = 0; cellRow < rooms[r][c].getMaxRows(); ++cellRow) 
      { 
       xOffset = 0; 
       for (int cellCol = 0; cellCol < rooms[r][c].getMaxCols(); ++cellCol) 
       { 
        rooms[r][c].setupCell(cellRow, cellCol, startX + xOffset, startY - yOffset, textureHandler->getSpriteWidth(), textureHandler->getSpriteHeight(), false, textureHandler->getSpriteTexCoords("grass")); 
        xOffset += textureHandler->getSpriteWidth(); 
       } 
       yOffset += textureHandler->getSpriteHeight(); 
      } 
     } 
    } 

    currentDungeon = dungeonID; 
    currentRoomRow = 0; 
    currentRoomCol = 0; 
} 

那麼如何加快速度,所以每次加載時間不需要大約15秒鐘。我覺得應該不需要15秒來加載一個簡單的2D遊戲。

SOLUTION 那麼我的解決辦法是使用std ::矢量::儲備調用(rooms.reserve在我的代碼,它結束了工作很好,我改變了我的功能地牢:: loadDungeon到地牢:: loadDefaultDungeon因爲現在加載關閉保存文件

反正這裏是代碼(我把它下降到約4-5秒鐘〜在調試模式下15 +秒):

Dungeon::Dungeon() 
{ 
    rooms.reserve(MAX_RM_ROWS * MAX_RM_COLS); 
    currentDungeon = 0; 
    currentRoomRow = 0; 
    currentRoomCol = 0; 
} 
void Dungeon::loadDefaultDungeon(TextureHandler* textureHandler, int topLeftX, int topLeftY) 
{ 
    int startX = topLeftX + (textureHandler->getSpriteWidth()/2); 
    int startY = topLeftY - (textureHandler->getSpriteHeight()/2); 
    int xOffset = 0; 
    int yOffset = 0; 
    cerr << "Loading default dungeon..." << endl; 
    for (int roomRow = 0; roomRow < MAX_RM_ROWS; ++roomRow) 
    { 
     for (int roomCol = 0; roomCol < MAX_RM_COLS; ++roomCol) 
     { 
      rooms.push_back(Room()); 
      int curRoom = roomRow * MAX_RM_COLS + roomCol; 
      for (int cellRow = 0; cellRow < rooms[curRoom].getMaxRows(); ++cellRow) 
      { 
       for (int cellCol = 0; cellCol < rooms[curRoom].getMaxCols(); ++cellCol) 
       { 
        rooms[curRoom].setupCell(cellRow, cellCol, startX + xOffset, startY - yOffset, textureHandler->getSpriteWidth(), textureHandler->getSpriteHeight(), false, textureHandler->getSpriteTexCoords("default"), "default"); 
        xOffset += textureHandler->getSpriteWidth(); 
       } 
       yOffset += textureHandler->getSpriteHeight(); 
       xOffset = 0; 
      } 
      cerr << "  room " << curRoom << " complete" << endl; 
     } 
    } 
    cerr << "default dungeon loaded" << endl; 
} 

Room::Room() 
{ 
    cells.reserve(MAX_ROWS * MAX_COLS); 
    for (int r = 0; r < MAX_ROWS; ++r) 
    { 
     for (int c = 0; c < MAX_COLS; ++c) 
     { 
      cells.push_back(Cell()); 
     } 
    } 
} 
void Room::setupCell(int row, int col, float x, float y, float width, float height, bool solid, /*std::array<float, 8>*/ vector<float> texCoords, string texName) 
{ 
    cells[row * MAX_COLS + col].setup(x, y, width, height, solid, texCoords, texName); 
} 

void Cell::setup(float x, float y, float width, float height, bool solid, /*std::array<float,8>*/ vector<float> t, string texName) 
{ 
    this->x = x; 
    this->y = y; 
    this->width = width; 
    this->height = height; 
    this->solid = solid; 
    for (int i = 0; i < t.size(); ++i) 
     this->texCoords.push_back(t[i]); 
    this->texName = texName; 
} 
+0

你正在編譯優化嗎?標準庫容器是_templates_,它們從編譯器優化中受益匪淺。 – Blastfurnace 2012-07-22 22:48:48

+0

@Blastfurnace如何打開它們? – Steven 2012-07-22 22:59:08

+1

嘗試一個平坦的一維矢量,大步訪問。另外,提前預留足夠的空間。 – 2012-07-22 23:02:55

回答

3

似乎浪費,有這麼多的動態分配,可以通過做這樣的事情來完成。您可以通過壓扁了您的載體和進步訪問它擺脫單一的分配:

std::vector<Room> rooms; 

rooms.resize(MAX_RM_ROWS * MAX_RM_COLS); 

for (unsigned int i = 0; i != MAX_RM_ROWS; ++i) 
{ 
    for (unsigned int j = 0; j != MAX_RM_COLS; ++j) 
    { 
     Room & r = rooms[i * MAX_RM_COLS + j]; 
     // use `r`  ^^^^^^^^^^^^^^^^^^^-----<< strides! 
    } 
} 

注意如何resize是精確的進行一次,招致只有一個單一的分配,以及默認構造每個元素。如果你想特別構建每個元素,請改爲使用rooms.reserve(MAX_RM_ROWS * MAX_RM_COLS);,並在循環中填充該向量。

您可能還希望通過交換行和列來查看哪些更快。

+0

無論如何,你coudld解釋'房間&r =房間[我* MAX_RM_COLS + j];'稍微進一步?不太確定那裏發生了什麼。 – Steven 2012-07-22 23:15:50

+0

@Flappy:我只是用一個計數器來枚舉一個二維空間。這是一種方法,你可以將矩形中的單元格逐行排列並環繞。 – 2012-07-22 23:20:12

+0

讓我試試這個......所以當你到達那條線時,你正在創建一個叫做'r'的新房間,指向當前列的位置。 [i * MAX_RM_COLS + j] 0-4的結果在行0中,5-9在行1中,等等。所以它就像一個二維數組。我接受它我會用'r'來操作數組中的房間?例如:r = Room(); (對於默認的初始化)? 我通過了嗎?大聲笑 – Steven 2012-07-22 23:37:21

3

因爲它似乎是你的向量的大小在編譯時定義,如果你可以使用C++ 11,你可以考慮使用std::array而不是std::vectorstd::array無法調整大小,並且缺少std::vector中的許多操作,但它更輕巧,它看起來非常適合您正在進行的操作。

作爲一個例子,可以聲明cells爲:

#include <array> 

/* ... */ 

std::array<std::array<Cell, MAX_COLS>, MAX_ROWS> cells; 

UPDATE:由於本地定義的std::array分配堆棧在其內陣列中,OP將經歷一個堆棧溢出,由於相當大的陣列的大小。儘管如此,通過在堆上分配數組,可以使用std::array(及其優點與使用std::vector相比)。

typedef std::array<std::array<Cell, MAX_COLS>, MAX_ROWS> Map; 
Map* cells; 

/* ... */ 

cells = new Map(); 

更妙的是,智能指針可以使用:

#include <memory>  

/* ... */ 

std::unique_ptr<Map> cells; 
cells = std::unique_ptr(new Map()); 
+0

我使用數組得到堆棧溢出錯誤,正如我最初在問題中所述。 – Steven 2012-07-22 22:43:52

+0

@Flappy你使用C++ 11數組還是純C類數組?他們是完全不同的東西。 – betabandido 2012-07-22 22:44:37

+0

@Flappy一個簡單的C類數組不是一個對象,而只是一個數據類型。 'std :: array'是一個STL類,就像'std :: vector'一樣,但是數組的大小不能動態改變,因爲它是vector的情況。 'std :: array'最近在C++ 11中引入,所以你需要一個相對較新的編譯器。在這裏你可以描述[新的C++ 11特性](http://en.wikipedia.org/wiki/C%2B%2B11)。你可以在我的答案中找到描述'std :: array'的鏈接。 – betabandido 2012-07-22 23:02:59