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

Bha*_*v B 2 c++ virtual inheritance function segmentation-fault

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

//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
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

void Camera::parse(ifstream &infile){
  //do parsing stuff
}
Run Code Online (Sandbox Code Playgroud)

parse()在头文件中声明为虚拟void parse(ifstream&);

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

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

任何帮助,将不胜感激 :)

Use*_*ess 8

你不能(只是)malloc一个非POD对象,你必须这样new做.

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

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


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

具体来说,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;
Run Code Online (Sandbox Code Playgroud)

但这是更好的风格:

std::unique_ptr<Camera> camera(new Camera);
camera->parse(file);
// destruction handled for you
Run Code Online (Sandbox Code Playgroud)

并且只有当你真的需要使用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);
Run Code Online (Sandbox Code Playgroud)