2014-02-15 64 views
1

我有一个叫做块的对象,它包含一个指向b2Body的指针。它做了其他重要的事情,但为了简单起见我删除了这些内容开头,智能指针不起作用(我想),你会明白为什么。不同的析构函数类型?

class DChunk 
{ 
public: 
    DChunk(); 

    DChunk(const DChunk& old); 
    virtual ~DChunk(); 

    virtual b2Body* getBody() const; 

private: 
    b2Body* m_pBody;//pointer; 
}; 

问题是,如何定义何时删除m_pBody对象。

如果我想复制这个对象,就像说有这些东西的向量,我push_back另一个,它会调用复制构造函数,复制m_pBody的内存地址(多数民众赞成我想要的),然后删除旧的。如果该对象的析构函数删除m_pBody,这显然是不好的,因为新的副本不会有一个有效的内存地址,但如果不删除它,然后m_pBody将永远不会被删除,而它需要被删除时,有没有更多的块指向它。

删除m_pBody对象的唯一正确的方法是调用m_pBody-> GetWorld() - > DestroyBody(m_pBody);那不在我的控制之下,所以聪明的指针并不真正起作用。 我希望能有适当调用的不同类型的析构函数,比如在向量中创建副本时。另外,如果有帮助的话,应该永远不会有多个与一个b2Body相关联的块。

+0

'm_pBody'必须是指针吗? – LihO

+3

您可以使用具有自定义删除器的智能指针。 C++ 11提供它们,Boost拥有它们,你也可以自己创建。 – Cornstalks

+0

1.是的,必须是指针。 2.我不认为我有权访问C++ 11。如果我真的需要,我想我可以使用Boost,但我宁愿避免将更多的库放入此项目。我打算自己做,但我认为有一个更经典的方式来处理它。 –

回答

1

我会假设你有类似

vector<DChunck> myvec; 

和你是担心这样做

obj=DChunk() 
    myvec.push_back(obj) 

首先(这是非常初学者友好的方式,避免了智能指针或任何C++ 11)关于创建容器DChunk对象有一些不太正确的地方。这是因为当你声明

vector<DChunk> 

你告诉你的向量,它会接收对象的大小DChunk。 然而,由于类包含一个指向数组的指针,m_pBody(数组的大小将不是恒定!),这种方法不会对C过于“健康” ++。 考虑到这一点,你可以做别的事情,坚持你的类设计:创建一个指针的容器! 您可以创建

vector<DChunk*> myvec; 

,如果你想将一个对象添加到向量,你只是做

DChunk *obj = new DChunk(); 
    myvec.push_back(event); 

因为现在容器处理指针,可周围没有与干扰被篡改对象内容,避免了有关析构函数的担忧。 调用对象的方法现在是,例如,

(*myvec[3]).getBody() 

或(清洁版)

myvec[3]->getBody() 

希望我解决你的问题

+0

是的,我知道这也是一种选择,我也在项目的其他部分做到了这一点,但是我试图避免使用指针向量,因为在解引用中有开销。当然,除非这个对象真的很大。但我想在这种情况下,这将是最好的解决方案。 虽然其他一些东西,m_pBody不是一个数组。具有讽刺意味的是,DChunk确实包含了一个指向向量,我将它移除以便于阅读。 –

+0

好吧,关于这个指针设计容器的好处是,它是如此多才多艺,你不必关心你的对象内部是什么。但是,如果DChunk对象本身包含一个指针向量,那可能会有点棘手! – user3264316

0

您也可以提供移动构造函数,这样的而不是复制,它会移动的东西...下面是我的一些天前做出了表率,因为我有同样的问题(我不知道以什么顺序将这些构造函数和被调用时,也是“& &”是移动构造函数):

移动构造函数类似于复制构造函数。不同的是,在移动构造函数中,而不是复制值和东西,您将给定的对象的指针(不是复制)和值分配给一个新的(this-> temp = OldClass.temp),然后使OldClass.temp = NULL;所以当不可避免的析构函数被调用时,它会找到一个NULL指针并且不会将其删除。

#include <iostream> 
#include <Windows.h> 

class MyClass 
{ 
public: 
    MyClass() 
    { 
     temp = new RECT(); 
     ZeroMemory(temp, sizeof(RECT)); 
    } 
    MyClass(int x, int y) 
    { 
     temp = new RECT(); 
     ZeroMemory(temp, sizeof(RECT)); 
     temp->left = x; 
     temp->top = y; 
    } 
    MyClass(MyClass &&OldClass) 
    { 
     if (this->temp != NULL) 
     { 
      delete this->temp; 
      this->temp = NULL; 
     } 
     temp = OldClass.temp; 
     OldClass.temp = NULL; 
    } 
    MyClass& operator=(MyClass &&OldClass) 
    { 
     if (this->temp != NULL) 
     { 
      delete this->temp; 
      this->temp = NULL; 
     } 
     temp = OldClass.temp; 
     OldClass.temp = NULL; 
     return *this; 
    } 
    MyClass(const MyClass &OldClass) 
    { 
     *temp = *OldClass.temp; 
    } 
    MyClass& operator=(const MyClass &OldClass) 
    { 
     *temp = *OldClass.temp; 
     return *this; 
    } 
    ~MyClass() 
    { 
     if (this->temp != NULL) 
     { 
      delete this->temp; 
      this->temp = NULL; 
     } 
    } 
    void Print() 
    { 
     std::cout << temp << " " << temp->left << " " << temp->top << " " << temp->right << " " << temp->bottom << '\n'; 
    } 
private: 
    RECT *temp; 
}; 

int main() 
{ 
    MyClass bla, cha(54, 48); 
    bla.Print(); 
    cha.Print(); 
    bla = MyClass(2, 2); 
    bla.Print(); 
    bla = cha; 
    bla.Print(); 
    cha = MyClass(54, 2); 
    cha.Print(); 
    std::cin.get(); 
    return 0; 
} 
+0

谢谢你的评论,这可能是我想要的,但我不完全明白发生了什么事你能解释一下吗? –

+0

一个移动构造函数需要'C++ 11',如果不是'像'boost''这样的其他库'模拟',在这一点上其他的选项是更好的方式,它仍然没有解决问题的主要焦点。 – user2485710

+0

那么,与DirectX9相同的故事...为什么使用一个新的,当我们可以使用10岁(如果我认为它是正确的,它在2004年发布)。现在应该强制使用C++ 11 – FrogTheFrog

0

在共同的,一个正确的内存管理是不平凡任务和没有普遍的决定是存在的。一些简单和常见的众所周知的方法在最新的库中被呈现为“智能指针”类型(您也可以自己定义它们(通过复制已知的“标准定义”))。但它也不是完全通用的:-) 而你的问题似乎是一个这样的通用解决方案的问题。 一些其他编程语言(Java ...,而不是C++)宣传你摆脱了这个问题(通过内置的语言实现方法)。 你写道:“另外,如果有帮助,应该永远不应该有一个以上的块与一个b2Body相关联。” 。然后这个问题似乎消失了(因为块根本不能被复制)。 (?)

+1

正确的内存管理是一项非常简单的任务。您在需要时分配内存,并在不再使用时释放内存。真正的问题是恰当地描述每个对象的生命周期以及它们的内容之间的交互。另外,我不会不小心推荐所谓的“智能指针”。事实上,这是相当重的机器,如果使用不当,会产生很大的性能影响。许多C++程序员和公司甚至在不需要它们时使用它们 - 只是因为其他人都使用它们。 –

相关问题