初始化类成员引用变量,就像它是常规变量一样

Sky*_*leh 5 c++ variables reference

现在,我正在为我正在开发的游戏编写物理引擎.通常,当您将物理引擎与游戏引擎结合使用时,会有许多重复值.例如表示对象的位置和旋转的变量.对于大多数物理引擎,您必须遍历所有对象并根据物理引擎的对象位置更新其位置.所以我认为最好让物理引擎对象中的位置和旋转值引用游戏引擎对象处理旋转和位置的变量.但是,有时您希望物理引擎中的对象不直接与游戏引擎中的对象相关联.(隐形墙,关节).因此,您需要将对象视为常规成员变量......所以这就是我所拥有的.

struct object{
  float & xPosition;
  float & yPosition;
  float & zPosition;
  ...
  object(float & xPos, float& yPos, float& zPos):xPosition(xPos), yPosition(yPos), zPosition(zPos){}
  object():xPosition(*new float(0.0f)), yPosition(*new float(0.0f)), zPosition(*new float(0.0f)){}
};
Run Code Online (Sandbox Code Playgroud)

但是,这将导致内存泄漏,因为这些浮动没有被删除.对于如何在没有内存泄漏的情况下实现所需行为,您有什么建议吗?

编辑

我宁愿不使用boost.但是,我并不反对需要模板的解决方案.此外,这部分是性能优化,boost :: shared_ptr,似乎不是正确的解决方案.

Mik*_*son 5

我建议你使用boost::shared_ptr这些位置结构.这样,您不必担心删除,您可以将其用作与游戏引擎对象共享的指针或作为独立指针.

由于存在这些开销,您可能希望限制数据与指针的比率.换句话说,不要shared_ptr为每个坐标保持a ,而是保持shared_ptr位置矢量和a shared_ptr到旋转代表,或者a shared_ptr到均匀变换或帧(坐标系,动力学框架或动静帧).

例如,你可以这样:

class object {
  public:
    typedef boost::shared_ptr<Vector3D> pVector3D;
  private:
    pVector3D position;
  public:
    object(pVector3D aPos = pVector3D(new Vector3D(0.0,0.0,0.0))) : position(aPos) { };
};
Run Code Online (Sandbox Code Playgroud)

shared_ptr的自动和引用计数属性将使您不必担心放置删除语句(自动),并且物理引擎仍然需要这些变量时没有对象从游戏引擎中消失的危险(引用计数保证只有在删除了所有需要它们的对象时才会删除它们).

编辑

我宁愿不使用boost.但是,我并不反对需要模板的解决方案.此外,这部分是性能优化,boost :: shared_ptr,似乎不是正确的解决方案.

好吧,shared_ptr/ shared_array也可以在标准库技术报告1(TR1)中找到(所以它是std::tr1::shared_ptr相反的,所以你不需要使用Boost来使用它们).至于性能优化,这就是为什么我建议使用相当高的数据到指针比例.shared_ptr的开销主要是内存开销和删除和复制期间的一些间接(这是两个经常没有完成的操作),我认为与常规数据相比,访问它指向的数据的开销并不大.指针或引用.你必须接受这一点,即使使用引用,你也在交换带有数据访问间接开销的数据复制开销(你也牺牲了内存局部性,这是一个大问题!).我会说,与内存局部性相关的性能下降将远远超过单独的间接性.因此,当涉及访问元素时,IMO,shared_ptr,原始指针和引用将具有非常小的性能差异.在许多使用这些共享变量的算法中,最好将指针/引用指向的数据复制到局部变量,用这些局部变量计算,然后将它们复制回指针所指向的内存中. /参考.

我建议你在使用任何一种解决方案(使用shared_ptr,使用引用或原始指针,以及在游戏引擎和物理引擎之间复制数据)时对性能进行一些测试,并亲眼看看,你可能会惊讶于什么你发现.

EDIT2

您是否考虑过使用多重继承方案?钻石继承方案可能很好地解决了这个问题:

class PositionedObject {
  protected:
    float Position[3];
  public:
    PositionedObject(float x,float y, float z) { Position[0] = x; ... };
    virtual ~PositionedObject() { };
};

class VisibleObject : virtual public PositionedObject { //note that the "virtual" keyword is critical here.
  ... rendering-related code ... i.e. the game-engine side of the implementation
};

class RigidBody : virtual public PositionedObject { //again "virtual" is very important.
  ... physics code here ...
};

class MyObject : public VisibleObject, public RigidBody {
  ... code specific to MyObject ...
};
Run Code Online (Sandbox Code Playgroud)

上述方案使物理对象和游戏引擎对象共享相同的位置数据(间接很少,内存开销很小,内存局部性问题很少).我很确定这比其他任何方案都更有效率,但关于性能的争论只能通过你必须自己做的测试结果来回答,如果性能确实是你最关心的问题(确保你没有做到)过早优化!).


Ben*_*ley 1

做你现在正在做的事情,只需保留一个额外的 bool 变量来指示你的内存是否已分配。然后,在析构函数中,您可以在检查该值后调用delete,即

struct object{
  float & xPosition;
  float & yPosition;
  float & zPosition;

  object(float & xPos, float& yPos, float& zPos)
    :xPosition(xPos),
     yPosition(yPos),
     zPosition(zPos),
     allocated(false)
  {}
  object()
    :xPosition(*new float(0.0f)),
     yPosition(*new float(0.0f)),
     zPosition(*new float(0.0f)),
     allocated(true)
  {}

  ~object() {
    if(allocated) {
      delete &xPosition;
      delete &yPosition;
      delete &zPosition;
    }
  }

private:
  bool allocated;
};
Run Code Online (Sandbox Code Playgroud)