【问题标题】:Crash/Segfault in calling virtual member of subclass调用子类的虚拟成员时崩溃/段错误
【发布时间】:2012-04-04 23:48:21
【问题描述】:

我一直试图让这段代码工作但没有成功。 gdb 告诉我 void Compiler::GenerateCode_ToFile(char* filename) 函数中某处存在段错误,我已手动将问题追溯到该行中的某处:

 std::string tempfile = this->code->CodeGen( temp, AST_TYPE_UNDEF, symtab, 0);

但不是在它之后或之前。此外,它似乎在该虚拟函数的任何代码运行之前崩溃。

谁能看到这里的问题?我只是看不出是什么导致它崩溃。 这是调用虚函数的函数:

void Compiler::GenerateCode_ToFile(char* filename){

char directory[MAX_PATH];   //Actually represents the full path.
strcpy( directory, this->cwd.c_str());
strcat( directory, filename);

if(this->isVerboseMode)
    std::cout << "Source Output: " << directory << '\n';

std::fstream file( directory, std::ios::out);

int* temp = new int;
Symtable* symtab = new Symtable;
file << emit_core_code();
file << "\n\n";
std::string tempfile = this->code->CodeGen( temp, AST_TYPE_UNDEF, symtab, 0);
file.close();
}

这是this->代码所代表的类的定义。

/// CollectionExprAST - Expression class for multiple branches.
class CollectionExprAST : public ExprAST {
  std::vector<ExprAST*>* Code;
public:
  CollectionExprAST(std::vector<ExprAST*>* code) : Code(code) {}
  virtual std::string CodeGen(int* GeneratedCodeOpType,int WantOpType,Symtable* symtab, int depth);
  int GetType(void){return AST_TYPE_COLLECTION;};
  void* GetCollection(void){return this->Code;};
  void DebugPrint(int level);
};

这是它的超类:

/// ExprAST - Base class for all expression nodes.
class ExprAST {
public:
  virtual ~ExprAST() {}
  virtual std::string CodeGen(int* GeneratedCodeOpType,int WantOpType,Symtable* symtab, int depth) {return std::string("");};
  virtual void DebugPrint(int level){return;};
  virtual int GetType(void){return AST_TYPE_UNDEF;};
  virtual void* GetCollection(void){return NULL;};
};

最后,这是被调用的虚函数(虽然它在运行之前似乎崩溃了):

std::string CollectionExprAST::CodeGen(int* GeneratedCodeOpType,int WantOpType,Symtable* symtab, int depth)
{
Sleep(3000);
std::string ret;
int j=0;
for(;j<this->Code->size();j++){
    int temp;
    int i=0;
    for(;i<depth;i++)
        ret += "\t";
    ret += (*this->Code)[j]->CodeGen(&temp,WantOpType,symtab, depth+1);
    ret += '\n';
}
return ret;
}

我知道它在运行之前会崩溃,因为 Sleep() 永远不会运行。

任何人都可以看到导致这个神秘的段错误的错误吗?

提前致谢。

【问题讨论】:

  • 代码太多。在此处发布您的代码之前,您需要构造一个minimal test-case。但是你确定吗? this-&gt;code 是一个有效的指针吗?
  • @OliCharlesworth 我比较确定它是一个有效的指针,因为我调用其他虚拟成员没有问题。
  • @64bit_twitchyliquid:你需要先构建一个最小的测试用例,然后这里的任何人才能给你具体的帮助。
  • @64bit_twitchyliquid: “相当肯定” 告诉我它可能不是。

标签: c++ class segmentation-fault virtual


【解决方案1】:

原因是code 未分配或损坏。

在运行函数之前检查nil,然后检查是否可以从该指针运行任何其他函数。第一个很明显,后者可能意味着指针在某处损坏。

【讨论】:

  • 毫秒之前,调用了一个不同的虚函数(DebugPrint())并且它运行正常。你确定代码有问题吗?
  • DebugPrint() 是否访问对象的任何字段?如果不是,则根本不会在对象上运行。
  • 是的。它几乎使用了所有这些。
  • 无论如何,请显示创建code 字段的代码,我们也许可以提供帮助。
  • @64bit_twitchyliquid:我根本看不到,我看到您传递了指向没有可用定义的函数的指针地址。这并不能告诉我或其他任何人分配已正确执行。
【解决方案2】:

我在您的示例中看不到您实际分配 Code 成员变量的地方。它是一个指针,它指向的东西需要在某个时候分配。

还有其他问题,尽管与您的崩溃没有直接关系。

首先,您永远不要删除GenerateCode_ToFile 中的symtabtemp。这是内存泄漏。就此而言,您到底为什么要在那里动态分配int?只需在堆栈上声明一个 int 并将其地址传递给 CodeGen 函数。如果可能,symtab 也是如此。

int i = 10;
SomeFuncThatTakesAPointer(&i);

实际上,仔细观察,您甚至没有在函数中使用int* 参数,它也没有保存在任何地方,所以完全摆脱它。

下一步...

std::vector<ExprAST*>* Code;

指向向量的指针和存储指针的向量几乎总是错误的。您正在阻止向量为您处理动态内存分配和释放。此时您不妨只使用一个数组(好吧,如果您分配超出其边界的东西,数组不会为您增长,但仍然是不好的做法)。

向量使用称为RAII 的模式为您安全地分配和释放内存。当您维护指向向量的指针时,您会绕过该过程,并且需要自己在向量上调用delete

当您将指针存储在向量中时,您再次阻止向量释放其存储的对象。它将动态存储指针本身并在它们上调用delete,但这不会释放原始指针指向的内容。

C++ 是一门复杂的语言。我建议花一些时间了解更多关于一般内存管理和模式(如 RAII)的知识,这可以为您简化流程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-15
    • 2021-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多