Segfault在调用派生类的虚函数时

时间:2013-04-08 20:58:42

标签: c++ function inheritance segmentation-fault virtual

当我调用派生类的虚函数时,我遇到了段错误的问题。但是,如果我将函数的名称更改为与基类中的虚函数的名称不同,则不会发生这些段错误。这是一些代码:

//in main
//initialize scene objects
//camera
if((camera = (Camera*)malloc(sizeof(Camera))) == NULL){
  cout << "Could not allocate memory for camera" << endl;
}
//...code in middle
//inside file parsing...
//infile is an ifstream
//nextString is a char*
if(!strcmp(nextString,"camera")){
  camera->parse(infile); //segfault here
}

这是基类头(.cpp仅在构造函数中实例化变量):

class WorldObj{
public:
  WorldObj();
  ~WorldObj();
  virtual void parse(ifstream&) =0;
  vec3 loc; //location
};

这是我用来编写虚函数的Camera类中的代码:

void Camera::parse(ifstream &infile){
  //do parsing stuff
}

parse()在头文件中声明为虚拟空分析(ifstream&amp;);

我的问题是,如果我将Camera内部的parse()重命名为CameraParse(),并完全忽略了要实现的虚函数这一事实,那么代码完全正常工作!

您是否可以了解为什么调用虚函数会导致段错误?我已经检查过Valgrind,看看是否有任何内存问题,它告诉我有8个字节的无效读/写。我明白这意味着我没有为我的对象正确分配内存,但我不知道我在哪里分配错误。

任何帮助将不胜感激:)

4 个答案:

答案 0 :(得分:8)

您不能(仅)malloc非POD对象,您必须new

这是因为malloc保留了适当的空间,但是没有构造对象,这对于任何具有虚函数的类都是非常重要的,即使构造函数是默认的

现在,只有当您进行虚函数调用时才会出现特定问题,因为这取决于new执行的额外初始化,但使用任何非构造的非构造实例仍然是错误的POD类型。


请注意,我正在使用POD( Plain Old Data )作为懒惰的简写,只需要进行简单的初始化。通常,如果一个类(或结构)既不是它,也不是它的任何成员或基类都有做某事的构造函数,那么它就可以简单地初始化。出于我们的目的,每个具有一个或多个虚方法的类(即使它们被继承,或者在数据成员中)都需要进行非平凡的初始化。

具体来说,Ben Voigt的答案中的标准引用描述了从对象的生命周期开始的两个阶段(您可以安全地进行方法调用的时间,特别是虚拟的):

  
      
  • 获得具有适当对齐和T型尺寸的存储,
  •   

当您致电malloc

时会发生这种情况
  
      
  • 如果对象具有非平凡的初始化,则其初始化完成
  •   

当您使用new时,对于非平凡初始化类型,只发生


作为参考,这是最接近现有代码的正常用法:

Camera *camera = new Camera;
// don't need to check for NULL, this will throw std::bad_alloc if it fails
camera->parse(file);
// don't forget to:
delete camera;

这是更好的风格,但是:

std::unique_ptr<Camera> camera(new Camera);
camera->parse(file);
// destruction handled for you

并且只有当确实需要使用malloc或其他特定分配器时才会这样做:

Camera *camera = (Camera *)malloc(sizeof(*camera));
new (camera) Camera; // turn your pointer into a real object
camera->parse(file);
// destruction becomes uglier though
camera->~Camera();
free(camera);

答案 1 :(得分:1)

使用new,而不是malloc。你分配了memmory,但没有创建对象。 使用new,使用相应的构造函数,将创建虚函数调度表,然后才能使用它。例如:

if((camera = new (nothrow) Camera()) == NULL){
  cout << "Could not allocate memory for camera" << endl;
}

if(!strcmp(nextString,"camera")){
  camera->parse(infile); //segfault here
}

或者你可以使用简单的

camera = new Camera;

在某处抓住可靠的异常bad_alloc。

答案 2 :(得分:1)

malloc不会调用构造函数。

你必须改变(C ++创建对象的方式)

camera = (Camera*)malloc(sizeof(Camera)))

camera = new Camera; // Now you camera object will be created and constructed.

答案 3 :(得分:1)

无用已提供正确的解释。以下是标准中的要求(第3.8节):

  

对象的生命周期是对象的运行时属性。如果一个对象属于类或聚合类型,并且它或其成员之一由除了普通默认构造函数之外的构造函数初始化,则称该对象具有非平凡的初始化。 [注意:通过简单的复制/移动构造函数进行初始化是非平凡的初始化。 - 结束说明]

     

类型为T的对象的生命周期始于:

     
      
  • 获取具有T类型的正确对齐和大小的存储,

  •   
  • 如果对象具有非平凡的初始化,则其初始化完成。

  •   
     

类型T的对象的生命周期在以下时间结束:

     
      
  • 如果T是具有非平凡析构函数的类类型,则析构函数调用将启动,或者

  •   
  • 重复使用或释放​​对象占用的存储空间。

  •