C ++ - 删除std :: string *;堆腐败

时间:2012-08-12 19:47:37

标签: c++ string memory-management

我对C ++内存管理比较陌生,而且我遇到了这个奇怪的堆损坏错误(在它之前加上Visual Studio中的自动断点)。这是违规代码:

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整数数组的形式(对于切片的ID)创建包含游戏世界数据的对象。

5 个答案:

答案 0 :(得分:7)

你的问题可能就在这里:

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

问题1:
它应该是-skip

tiles[i - skip] =

问题2:
atoi()命令使用不正确(tmp不包含字符串)。但我也不认为atoi()是合适的方法。我认为你要找的是简单的任务。从char到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.

一般来说,你不应该传递指针。在您需要指针的少数情况下,它们应该保存在智能指针对象或容器中(对于多个对象),以便正确控制它们的生命周期。

答案 1 :(得分:1)

atoi(&tmp); atoi期望一个指向空终止字符串的指针 - 而不是指向char的指针

答案 2 :(得分: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)而不是原始指针。

答案 3 :(得分:0)

中有一个错误
tiles[i+skip] = atoi(&tmp);

例如,对于字符串

Hello\n
World\n

对于i == 10点的循环迭代,skip已经为1(因为我们之前遇到过第一个\n)并且您正在写tiles[10 + 1] ,但tiles仅被分配为包含10个元素的数组。

答案 4 :(得分:0)

可能是变量输入是本函数的本地。因此从此返回后,内存被释放。因此,稍后调用此字符串上的delete会尝试释放已释放的内存。