2017-03-05 15 views
1

我目前正在为我正在做的课程做一个任务。我有什么似乎是一个完整的工作程序(我得到正确的输出所有我的测试数据),但是当我用valgrind运行它说我有内存错误。下面是最少的代码重现错误(这仍然是颇有几分不好意思):为什么我会用valgrind得到内存错误? (C++,抽象语法树评估)

注:此分配有关评估抽象语法树(不解析,只是评估)

头文件:(提供我的导师 - 我不能改变这一点)

struct env { 
    //will be used to store the values of variables in a stack. This is one 'node' of the stack 
    string var; 
    int value; 
    env *next; 
}; 

class Exp { 
    //general expression - eval will be overridden. 
public: 
    virtual int eval(env*) = 0; 
}; 

class Constant : public Exp { 
    int n; 
public: 
    Constant(int n) {this->n = n; } 
    int eval(env*); 
}; 

class Var : public Exp { 
    string name; 
public: 
    Var(string s) { this->name = s; } 
    int eval(env*); 
}; 

class Let : public Exp { 
    //let binding. (let bvar = bexp in body) 
    //used to assign a value to variables 
    string bvar; 
    Exp *bexp; 
    Exp *body; 
public: 
    Let(string v, Exp *e, Exp *b) 
    { 
     bvar = v; bexp = e; body = b; 
    } 
    int eval(env*); 
}; 

这是我写的,以评估语法的这个子集的代码:当我运行日

#include <string> 
using namespace std; 
#include "evalobj2.h" 

int Constant::eval(env *env) { 
    return this->n; 
} 

int Var::eval(env *env) { 
    while(env) { 
    if ((env->var).compare(this->name) == 0) return env->value; 
    env = env->next; 
    } 
    //give up - variable not found in env 
    throw 1; 
} 

int Let::eval(env *env) { 
    //make a new struct env to be pushed to the environment stack 
    struct env* newEnv = (struct env*)malloc(sizeof(struct env)); 

    //copy data into new env struct 
    newEnv->var = this->bvar; 
    newEnv->value = this->bexp->eval(env); 

    //make it the head of the "environment" so that it is seen first when looking up a value 
    newEnv->next = env; 

    //evaluate 
    int valToReturn = this->body->eval(newEnv); 
    free(newEnv); 

    return valToReturn; 
} 

从一个主要的方法,我从valgrind得到“6错误的6个错误”:

Exp *e = new Let("x",new Constant(1),new Var("x")); 
cout << e2->eval(nullptr) << endl; 

即使我得到正确的结果。我已经对更大的数据结构进行了测试,其余的语法都需要进行评估,所有这些都给出了正确的结果。

我不明白Valgrind在抱怨什么!它说“有条件的跳转或移动取决于未初始化的值”在“operator delete(void *)”....通过其他一些不是我的东西...通过Let :: eval(env *)... which是我的。

对于有内存错误的程序,我将得到0分。

+0

除了使用'malloc'而不是'new []','Exp'类需要一个虚拟析构函数。如果您尝试使用Exp * e = new Let(...)... delete e;''释放内存,则行为未定义。 – PaulMcKenzie

+0

*头文件:(由我的导师提供 - 我不能改变这个)* - 你的导师需要一个导师。如果您应该使用基类指针动态地创建从'Exp'派生的对象,并且(如应该要求的那样)解除分配内存,那么您的导师的头文件存在严重问题,因为如果不引入未定义的行为就无法完成,更可能的是,未定义的行为是内存泄漏。原因在我上面的第一条评论中提到。你的导师的等级为'F'。 – PaulMcKenzie

回答

3
struct env { 
    //will be used to store the values of variables in a stack. This is one 'node' of the stack 
    string var; 
    int value; 
    env *next; 
}; 

// ... 

struct env* newEnv = (struct env*)malloc(sizeof(struct env)); 

您分配env,用C++类,即std::string的结构,使用C库的malloc(),哪知道绝对没有关于C++类。

这是未定义的行为。必须使用newdelete分配和销毁C++类。令人惊讶的是,您的代码能够长久存活以产生任何结果,而不是崩溃和燃烧,从一开始就是如此。

1

你应该使用C++的内存分配:比如

int Let::eval(env *env) { 
    //make a new struct env to be pushed to the environment stack 
    env* newEnv = new env(); 

    //copy data into new env struct 
    newEnv->var = this->bvar; 

    ... 

    int valToReturn = this->body->eval(newEnv); 
    delete newEnv; 

    return valToReturn; 
} 

此外,这是很好的做法在构造函数初始化数据。至少:

struct env { 
    env() : next(0) {} 

    //will be used to store the values of variables in a stack. This is one 'node' of the stack 
    string var; 
    int value; 
    env *next; 
};