2012-08-12 46 views
1

我對C++內存管理比較陌生,而且我得到了這個堆損壞的奇怪錯誤(以及之前的Visual Studio自動斷點)。這是有問題的代碼:C++ - 刪除std :: string *;堆腐敗

z_world::z_world(char* name) 
{ 
    unsigned int i, skip; 
    char tmp; 

    //Load data from file 
    std::string* data = loadString(name); 

    //Base case if there is no world data 
    tiles = NULL; 

    w = 0; 
    h = 0; 

    if(data->length() > 0) { 
     //Set up the 'tiles' array 
     for(i = 0; i < data->length(); i++) { 
      if(data->at(i) == '\n') 
       h++; 
      if(h == 0) 
       w++; 
     } 
     tiles = new int[data->length()-h]; 

     //Load Data 
     skip = 0; 
     for(i = 0; i < data->length(); i++) { 
      if(data->at(i) == '\n') { 
       skip++; 
       printf("\n"); 
       continue; 
      } 
      tmp = data->at(i); 
      tiles[i+skip] = atoi(&tmp); 
      printf("%i ",tiles[i+skip]); 
     } 
    } 
    delete data; 
} 

此處,我在字符串中加載:

std::string* loadString(char* name) 
{ 
    ifstream in(name); 
    std::string* input = new string(); 

    while(in) { 
     std::string line; 
     getline(in,line); 
     input->append(line); 
     input->append("\n"); 
    } 

    in.close(); 

    return input; 
} 

我得到的內部斷點和錯誤「刪除數據;」,這讓我覺得「數據」在此之前的某個地方被刪除,但我找不到它會在哪裏。作爲參考,這種方法是創建一個包含遊戲世界數據的對象,其形式爲虛擬2D整數數組(用於tile的ID)。

+6

你會更好的只是返回一個字符串的價值和忘記所有關於內存管理。 – juanchopanza 2012-08-12 19:50:11

+2

你確定它是'tiles [i + skip]'而不是'tiles [i-skip]'嗎? – kennytm 2012-08-12 19:51:09

+1

其他地方的數據不會被刪除 - 但它可能會被破壞,因爲您正在寫入超出tiles數組的範圍。 2修正:1)不要使用原始指針,但智能指針或通過值傳遞std :: string 2)使用std :: vector < int >而不是原始數組 – stijn 2012-08-12 19:52:16

回答

7

特殊照顧的問題很可能是在這裏:

tiles[i+skip] = atoi(&tmp); 

問題1:
應該-skip

tiles[i - skip] = 

問題2:
atoi()命令使用不正確(tmp不包含字符串)。但我也不認爲atoi()是合適的方法。我認爲你正在尋找的是簡單的任務。從炭爲int的轉化是自動的:

tiles[i - skip] = tmp; 

問題3:
您沒有正確地使用對象。在這種情況下,不需要生成動態對象,並創建動態內存管理混亂。創建自動對象並正常傳遞它們會更簡單:

std::string* loadString(char* name) 
     // ^Don't do this. 



std::string loadString(std::string const& name) 
// ^^^^^^^ return a string by value. 
//   The compiler will handle memory management very well. 

一般而言,您不應該傳遞指針。在少數情況下,你確實需要指針,它們應該被保存在一個或多個智能指針對象中,以便正確控制它們的壽命。

+0

這工作,謝謝!堆損壞錯誤是由問題1引起的,但我也根據您和其他人的建議修復了其他問題。 – Omegalisk 2012-08-12 20:08:34

+0

你還應該看看:'tiles = new int [data-> length() - h];'另一個不需要的新的使用。傾向於使用'std :: vector '作爲子對象的容器。 – 2012-08-12 20:10:18

0

沒有必要在您顯示的代碼中動態分配字符串。更改loadString功能

std::string loadString(char* name) 
{ 
    ifstream in(name); 
    std::string input; 

    // ... 

    return input; 
} 

在來電

std::string data = loadString(name); 

現在有沒有必要delete大功告成後的字符串。

代替

int *tiles = NULL; 
tiles = new int[data->length()-h]; 

使用

std::vector<int> tiles; 
tiles.resize(data.length() - h); 

另外,如果你確實需要動態分配你應該使用智能指針(std::unique_ptrstd::shared_ptr)而不是原始指針對象。

+2

我不確定這是否真的是問題。他用新的分配,然後刪除一次,無論問題是什麼,它都可能在棧上顯示出來。 – enobayram 2012-08-12 19:56:05

+0

@enobayram這不是他看到的堆腐敗的原因,這可能與覆蓋'tiles'數組的邊界有關,如上面註釋中@stijn所述。 – Praetorian 2012-08-12 19:57:39

1

atoi(&tmp); 的atoi需要一個指向一個空結束的字符串 - 不是一個指針爲char

0

有一個在

tiles[i+skip] = atoi(&tmp); 

例如一個bug,對於字符串

Hello\n 
World\n 

並在i == 10點的循環迭代,skip已經是1(因爲我們遇到的第一個\n之前),並且您正在寫入tiles[10 + 1],但tiles僅被分配爲包含10個元素的數組。

0

可能是該函數的局部變量輸入。所以從這裏返回後,內存被釋放。因此,稍後調用刪除此字符串時會嘗試釋放已釋放的內存。