为什么我在使用 valgrind 时会出现内存错误? (C++,抽象语法树求值)

Why am I getting memory errors with valgrind? (C++, abstract syntax tree evaluation)

我目前正在为我正在学习的课程做作业。我有一个似乎可以正常工作的程序(我得到了所有测试数据的正确输出),但是当我使用 valgrind 运行 时,它说我有内存错误。这是重现错误的最少代码(仍然很抱歉):

注意:这个作业是关于评估抽象语法树(不是解析,只是评估)

头文件:(由我的导师提供 - 我无法更改)

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*)" 上写着 "Conditional jump or move depends on uninitialised values" .... 通过一些其他不是我的东西... 通过 Let::eval(env*) ... 这是我的。

如果程序存在内存错误,我将获得 0 分。

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++ 完全一无所知 类.

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

你应该使用 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;
};