2012-08-12 62 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

可能是该函数的局部变量输入。所以从这里返回后,内存被释放。因此,稍后调用删除此字符串时会尝试释放已释放的内存。