2010-04-10 66 views
0

單步執行調試器時,BBox對象在函數的入口處沒問題,但一旦進入函數,vfptr對象就會指向0xccccc。我不明白。爲什麼這個對象弄出來並被刪除?

  1. 這是什麼原因造成的?
  2. 當對象不是從其他類派生時,爲什麼在那裏存在一個虛擬表引用。 (儘管它駐留在我的Player類繼承的GameObject中,並且我從玩家內部檢索了BBox,但是,爲什麼BBox有參考價值?難道它不應該是參與者應該維護的玩家嗎?)

For 1;一些供參考的代碼:

答:我從播放器中檢索邊界框。按預期返回一個邊界框。然後我將它的地址發送給GetGridCells。

const BoundingBox& l_Bbox = l_pPlayer->GetBoundingBox(); 

boost::unordered_set < Cell*, CellPHash >& l_GridCells = GetGridCells (&l_Bbox); 

B.這是a_pBoundingBox變得瘋狂並且得到垃圾值的地方。

boost::unordered_set< Cell*, CellPHash > CollisionMgr::GetGridCells(const BoundingBox *a_pBoundingBox) 
{ 

我認爲下面的代碼也是相關的,所以我在此堅持反正這裏:

const BoundingBox& Player::GetBoundingBox(void) 
{ 
return BoundingBox(&GetBoundingSphere()); 
} 

const BoundingSphere& Player::GetBoundingSphere(void) 
{ 
BoundingSphere& l_BSphere = m_pGeomMesh->m_BoundingSphere; 

l_BSphere.m_Center = GetPosition(); 

return l_BSphere; 
} 

// BoundingBox Constructor 
BoundingBox(const BoundingSphere* a_pBoundingSphere); 

任何人都可以請給我一些想法,爲什麼發生這種情況?另外,如果你想讓我發佈更多的代碼,請讓我知道。

謝謝!

+0

什麼叫「一根筋了」是什麼意思? – 2010-04-10 08:21:17

+0

@Eli:當它到達GetGridCells時,對象超出範圍(..) 我不好使用正確的術語。 – brainydexter 2010-04-10 10:38:51

回答

3
const BoundingBox& Player::GetBoundingBox(void) 
{ 
return BoundingBox(&GetBoundingSphere()); 
} 

在這裏,您將返回對臨時對象BoundingBox的引用。只要return聲明結束,該對象就會超出範圍。

改爲返回BoundingBox而不是BoundingBox&


另外:

BoundingSphere& l_BSphere = m_pGeomMesh->m_BoundingSphere; 

l_BSphere.m_Center = GetPosition(); 

在這裏,你走上m_pGeomMesh的包圍球的參考,然後修改它指的是價值。這將導致原始對象的修改。你確定這是你想要的嗎?


另外:

// BoundingBox Constructor 
BoundingBox(const BoundingSphere* a_pBoundingSphere); 

在使用參考使得意義上的極大的唯一的地方,你用一個指針代替。爲什麼?

+0

但它返回一個const引用。在持有引用的調用者超出範圍之前,該對象是否保證有效?我同意如果它是非常量引用,它會是問題。但我依稀記得,const引用有特殊的規則。 – Naveen 2010-04-10 08:21:59

+2

確實有這樣的規則,但這不適用於此。對象的'const'引用在'return'語句中創建,然後作爲返回值複製,然後原始'const'引用超出範圍並且對象被銷燬。 (其他人可能會糾正我的技術細節,但我很確定這個'const'參考不會延長任何事情的範圍。) – Thomas 2010-04-10 08:39:45

+1

Thomas是對的。如果函數返回一個臨時值,並且該臨時值被綁定到引用,那麼生命期將被延長。但是在這種情況下,暫時的功能是內部的。考慮如果這些函數是在兩個不同的翻譯單元中,那麼編譯器不可能知道函數返回的引用是否指向臨時的。 – 2010-04-10 09:44:03

0
  1. 正如托馬斯說,該BoundingBoxreturn語句創建和銷燬在return語句的結束,因爲它是一個臨時的。返回一個const引用不同於分配給一個持久化const引用(這會延長一個臨時引用)。返回值並將其分配給調用者作用域中的某個值時,由於複製精度而沒有開銷,但您可能必須定義複製構造函數。
  2. 如果該類具有任何虛擬方法(如析構函數),則會創建該vtable。如果派生類重寫了這些方法,則將需要基本vtable來查找正確的重寫。所有這些都可能發生在另一個編譯單元中,因此編譯器不太可能優化它。
+0

第一點是正確的,但我已經嘗試過三次閱讀第二點,並且不理解它。 – 2010-04-10 09:45:20

+0

我理解關於第一點的第一個答案。關於第二個答案,我有個問題:(但在此之前,這裏是一些背景) - 玩家繼承遊戲對象(將覆蓋析構函數/更新/渲染方法) - 遊戲對象包含BoundingSphere所 現在,我明白它需要VTABLE到解決正確的課堂。但是,那麼爲什麼/如何將這些信息存儲在BoundingSphere中。我會假設vtable只能在Player對象中找到..請在這一個上糾正我。 謝謝 – brainydexter 2010-04-10 10:17:21

+0

@brainy:BoundingSphere不應該僅僅包含一個vtable,因爲它在某個類中創建了一個成員。 '虛擬'必須在其定義的某處使用。隨意發佈更多的代碼在你的問題。 – Potatoswatter 2010-04-10 17:23:57

0

@Thomas:這裏m個類:

#ifndef BOUNDINGBOX_H 
#define BOUNDINGBOX_H 

class BoundingSphere; 

class BoundingBox 
{ 
public: 

    BoundingBox(const BoundingSphere* a_pBoundingSphere); 
    //BoundingBox(const BoundingBox& rhs); 
    virtual ~BoundingBox(void); 

    const std::vector<glm::vec3> GetCorners() const; 

    glm::vec3 m_Center; 
    glm::vec3 m_Extents;  // extents along the X, Y, Z axis for the bounding box positioned at the center 
}; 

#endif 

#ifndef BOUNDINGSPHERE_H 
#define BOUNDINGSPHERE_H 

class BoundingBox; 

class BoundingSphere 
{ 
public: 
    BoundingSphere(); 

BoundingSphere(const BoundingBox* a_pBoundingBox); 

    BoundingSphere(const glm::vec3& a_Center, const float& a_Radius); 
    virtual ~BoundingSphere(void); 

    // Access the Center 
    const glm::vec3 &GetCenter(void) const { return(m_Center);  }; 
    void SetCenter(const glm::vec3 &Center) { m_Center = Center; }; 

    // Access the Radius 
    float GetRadius(void) const  { return(m_Radius);  }; 
    void SetRadius(float Radius) { m_Radius = Radius; }; 

    glm::vec3 m_Center; 
    float m_Radius; 
}; 

#endif 

現在,我明白這一點的方式是:如果在的BoundingBox的構造有BoundingSphere所參考而不是指針,即

BoundingBox(const BoundingSphere& a_pBoundingSphere); 

它需要在編譯時可以使用BoundingSphere的定義。因此,我必須在BoundingBox.h中包含BoundingSphere.h以使定義可用。這反過來也適用,從而創建循環引用。

請糾正我對這個..

感謝