当我不使用new或delete时,为什么会出现堆损坏?

时间:2014-06-19 06:57:34

标签: c++

TL; DR:永远记住std :: vector需要在数据增长时移动你的数据,这会使你仍然浮动的任何指针无效。

我已经搜索了一下这个问题,似乎我遇到的每个案例都是在同一个指针上调用delete两次的问题。我正在编写一个小程序而且我正在获得堆损坏,但堆分配的唯一事情就是c ++标准库。我有预感我正在泄漏对局部变量的引用或者做了多态的错误,但我无法弄明白。

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;

struct Project;
struct Solution;

struct Line {
    string command;
    vector<string> params;

    void print(ostream &os) {
        os << command << ": ";
        for (string s : params)
            os << s << ' ';
        os << endl;
    }
};

struct Properties {
    vector<string> includes;
    vector<string> libPaths;
    vector<string> libs;
    vector<string> sources;
    vector<string> headers;
    vector<Project *> depends;
    string folder;
    string name;
    string type;
};

struct Project : Properties {
    Project() { built = false; }

    bool built;

    void build() {
        if (built)
            return;
        built = true;

        for (Project *p : depends)
            p->build();

        cout << "Building project: " << name << endl;
    }
};

struct Solution : Properties {
public:
    Project *getProject(const string &name) {
        for (Project &p : projects) {
            if (p.name == name)
                return &p;
        }

        // No project with such a name -- create it
        Project p;
        cout << &p << endl;
        p.name = name;
        projects.push_back(p);
        cout << "Created project: " << name << endl;
        return getProject(name);
    }

private:
    vector<Project> projects;
};

Line parseLine(const string &strline) {
    istringstream stream(strline);
    Line line;

    stream >> line.command;
    while (stream.good()) {
        string tok;
        stream >> tok;
        if (tok.length() > 0)
            line.params.push_back(tok);
    }

    return line;
}

template <typename T>
vector<T> concat(const vector<T> &a, const vector<T> &b) {
    vector<T> vec;
    for (T obj : a)
        vec.push_back(obj);
    for (T obj : b)
        vec.push_back(obj);
    return vec;
}

template <typename T>
void printVector(ostream os, vector<T> v) {
    for (T obj : v)
        os << obj;
    os << endl;
}

int main(int argc, char *argv[]) {
    Solution solution;
    Properties *properties = &solution;
    ifstream stream("testproj.txt");

    Project p[100]; // No error here....

    string linestr;
    for (int lineNum = 1; getline(stream, linestr); lineNum++) {
        Line line = parseLine(linestr);

        if (line.command == "solution") {
            // Make future commands affect the solution
            properties = &solution;
        } else if (line.command == "exe" || line.command == "lib") {
            if (line.params.size() != 1) {
                cerr << "Error at line " << lineNum << endl;
                return 1;
            }

            // Make future commands affect this project
            properties = solution.getProject(line.params[0]);
            properties->type = line.command;
            properties->name = line.params[0];
        } else if (line.command == "includes") {
            properties->includes = concat(properties->includes, line.params);
        } else if (line.command == "libpath") {
            properties->libPaths = concat(properties->libPaths, line.params);
        } else if (line.command == "libs") {
            properties->libs = concat(properties->libs, line.params);
        } else if (line.command == "folder") {
            if (line.params.size() != 1) {
                cerr << "Error at line " << lineNum << endl;
                return 1;
            }

            properties->folder = line.params[0];
        } else if (line.command == "source") {
            properties->sources = concat(properties->sources, line.params);
        } else if (line.command == "header") {
            properties->headers = concat(properties->headers, line.params);
        } else if (line.command == "depends") {
            Project *proj;
            for (string projName : line.params) {
                proj = solution.getProject(projName);
                properties->depends.push_back(proj);
            }
        }
    }
}

错误:

HEAP: Free Heap block 00395B68 modified at 00395BAC after it was freed

这是我的堆栈跟踪(抱歉上面的源代码中没有行号):

crashes in malloc & ntdll somewhere up here
libstdc++ ---- incomprehensible name mangling
main.cpp, line 24 (inside Properties::Properties()): (compiler-generated constructor)
main.cpp, line 37 (inside Project::Project()): Project() { built = false; }
main.cpp, line 62 (inside Solution::getProject()): Project p;
main.cpp, line 150 (inside main()): proj = solution.getProject(projName);

它似乎在属性的默认构造函数中崩溃了?也许在构建矢量时?

编辑: 输入文件,如果有帮助:

solution
    includes deps/include deps/include/SDL2
    libpath deps/lib
    libs opengl32 glu32 SDL2main SDL2 libpng16 glew

exe game
    folder game
    source main.cpp
    depends render common

lib render
    folder render
    source Shader.cpp
    header TODO
    depends common

lib common
    folder common
    source util.cpp
    header TODO

1 个答案:

答案 0 :(得分:4)

这是很多代码,但有一个很大的可能性是你要取消引用getProject返回的指针之一,但这已经失效,因为向量projects,它持有指向的对象,已经执行了重新分配。这会使所有指针,引用和迭代器无效。

执行此操作时:

projects.push_back(p);

projects可能需要增长,这会导致重新分配和上面提到的指针无效。

如果不深入研究代码,看起来您可以使用Solution轻松实现std::map

struct Solution : Properties
{
public:
    // Check for project with name "name"
    // Add one if it doesn't exist
    // return it
    Project& getProject(const std::string& name) 
    {
      if (!projects.count(name))
      {
        projects[name].name = name;
      }
      return projects[name];
    }

    // Return project with name "name" or raise exception
    // if it doesn't exist
    const Project& getProject(const string &name) const
    {
      return projects.at(name);
    }
private:
    std::map<std::string, Project> projects;
};