导出类对象丢失vfptr的指针

duc*_*thd 1 c++ virtual-functions raytracing

首先,我试着写一个普通的,简单的Ray Tracer.在我的Ray Tracer中,我在世界上有多种类型的几何,都来自一个名为"SceneObject"的基类.我在这里列出了它的标题.

/**
Interface for all objects that will appear in a scene
*/
class SceneObject
{
public:
 mat4 M, M_inv;
 Color c;

 SceneObject();
 ~SceneObject();

 /**
 The transformation matrix to be applied to all points
 of this object.  Identity leaves the object in world frame.
 */
 void setMatrix(mat4 M);
 void setMatrix(MatrixStack mStack);
 void getMatrix(mat4& M);

 /**
 The color of the object
 */
 void setColor(Color c);
 void getColor(Color& c);

 /**
 Alter one portion of the color, leaving
 the rest as they were.
 */
 void setDiffuse(vec3 rgb);
 void setSpecular(vec3 rgb);
 void setEmission(vec3 rgb);
 void setAmbient(vec3 rgb);
 void setShininess(double s);

 /** 
 Fills 'inter' with information regarding an intersection between
 this object and 'ray'.  Ray should be in world frame.
 */
 virtual void intersect(Intersection& inter, Ray ray) = 0;

 /**
 Returns a copy of this SceneObject
 */
 virtual SceneObject* clone()  = 0;

 /**
 Print information regarding this SceneObject for debugging
 */
 virtual void print() = 0;
};
Run Code Online (Sandbox Code Playgroud)

如您所见,我已经包含了一些虚拟功能,可以在其他地方实现.在这种情况下,我只有两个派生类 - Sphere和Triangle,它们都实现了缺少的成员函数.最后,我有一个Parser类,它充满了实际的"光线跟踪"部分的静态方法.以下是相关部分的几个片段

void Parser::trace(Camera cam, Scene scene, string outputFile, int maxDepth) {
 int width = cam.getNumXPixels();
 int height = cam.getNumYPixels();
 vector<vector<vec3>> colors;
 colors.clear();
 for (int i = 0; i< width; i++) {
  vector<vec3> ys;
  for (int j = 0; j<height; j++) {
   Intersection intrsct; 
   Ray ray; cam.getRay(ray, i, j);
   vec3 color;
   printf("Obtaining color for Ray[%d,%d]\n", i,j);
   getColor(color, scene, ray, maxDepth);
   ys.push_back(color);
  }
  colors.push_back(ys);
 }
 printImage(colors, width, height, outputFile);
}

void Parser::getColor(vec3& color, Scene scene, Ray ray, int numBounces)
{
 Intersection inter; scene.intersect(inter,ray);
 if(inter.isIntersecting()){
  Color c; inter.getColor(c);
  c.getAmbient(color);
 } else {
  color = vec3(0,0,0);
 }
}
Run Code Online (Sandbox Code Playgroud)

现在,我已经放弃了真正的光线跟踪部分,而只是简单地返回第一个对象命中的颜色,如果有的话.毫无疑问,当计算机知道光线与物体相交时,唯一的方法是通过Scene.intersect(),我也包括它.使用的成员变量是"矢量对象",见end

好吧,现在为了这个问题.我首先创建一个场景并用Parser :: trace()方法之外的对象填充它.现在出于一些奇怪的原因,我为了i = j = 0投射Ray,一切都运行得非常好.但是,到第二条光线投射时,我场景中存储的所有对象都不再识别它们的vfptr(也就是说,我仍然可以访问除虚拟场景之外的所有SceneObject方法)!我使用调试器逐步调试代码,发现所有vfptr的信息都在getColor()结束和循环延续之间的某处丢失.但是,如果我将getColor()的参数更改为使用Scene&而不是Scene,则不会发生丢失.这是多么疯狂的伏都教?

场景代码,按要求:

#include <vector>
#include <limits>
#include "Intersection.h"
#include "LightSource.h"
#include "SceneObject.h"

using namespace std;

/**
Contains a list of scene objects.  A ray can be 
intersected with a scene to find its color
*/
class Scene
{
public:
    vector<SceneObject*> objects;
    vector<LightSource*> lights;

    Scene(void);
    ~Scene(void);

    /** 
    Add an object to the scene
    */
    void addObject(SceneObject& o);

    /**
    Add a light source to the scene
    */
    void addLight(LightSource& l);

    /**
    Fill 'l' with all light sources in the scene
    */
    void getLightSources(vector<LightSource*>& l);

    /**
    Fills 'i' with information regarding an
    intersection with the closest object in the scene
    IF there is an intersection.  Check i.isIntersecting()
    to see if an intersection was actually found.
    */
    void intersect(Intersection& i, Ray r);

    void print();
};

#include "Scene.h"

Scene::Scene(void)
{
}

Scene::~Scene(void)
{
    for(int i=0;i<objects.size();i++){
        delete objects[i];
    }
    for(int i=0;i<lights.size();i++){
        delete lights[i];
    }
}

void Scene::addObject(SceneObject& o)
{
    objects.push_back(o.clone());
}

void Scene::addLight(LightSource& l)
{
    lights.push_back(l.clone());
}

void Scene::getLightSources(vector<LightSource*>& l)
{
    l = lights;
}

void Scene::intersect(Intersection& i, Ray r)
{
    Intersection result;
    result.setDistance(numeric_limits<double>::infinity());
    result.setIsIntersecting(false);

    double oldDist; result.getDistance(oldDist);

    /* Cycle through all objects, making result
    the closest one */
    for(int ind=0; ind<objects.size(); ind++){
        SceneObject* thisObj = objects[ind];
        Intersection betterIntersect;
        thisObj->intersect(betterIntersect, r);

        double newDist; betterIntersect.getDistance(newDist);
        if (newDist < oldDist){
            result = betterIntersect;
            oldDist = newDist;
        }
    }

    i = result;
}

void Scene::print()
{
    printf("%d Objects:\n", objects.size());
    for(int i=0;i<objects.size();i++){
        objects[i]->print();
    }
}
Run Code Online (Sandbox Code Playgroud)

Bjö*_*lex 5

问题是你SceneObjects在析构函数中删除了你,Scene你使用默认的复制构造函数,它使用指针向量进行平面复制.这意味着,每个Scene引用的副本都相同SceneObjects.如果这些中Scene的一个被破坏,它们都会丢失它们被引用的对象.如果您通过引用传递场景,这没有问题,因为在这种情况下,不会进行任何复制并在以后销毁.