6

我希望我的类的析构函数删除整个对象,但其中一个成员除外,该成员在其他地方被删除。首先,这完全不合理吗?假设不是,我该怎么做?我认为创建一个带有空主体的析构函数会阻止所有成员被删除(因为析构函数不会做任何事情),但情况似乎并非如此。

4

12 回答 12

15

简短的回答:你没有。

更长的答案:如果“成员”实际上是指向其他分配的指针,您可以安排不删除其他分配。

但通常,如果你在构造函数中分配了另一个块,你想在析构函数中删除它。其他任何事情都需要仔细处理相关块的“所有权”。这将很像普通 c 中的内存管理。可能,但充满危险。

祝你好运。

于 2009-07-06T17:34:48.957 回答
10

取决于您所说的“已删除”是什么意思。如果它们不在智能指针中,并且没有被显式删除,那么它们不会被删除。只是类的一部分的成员:

class Bar {
//...
private: 
  Foo foo;
};

不会被析构函数删除(因为它们不是动态分配的),它们只是被销毁了。他们“生活”在课堂内,所以一旦被摧毁,它就消失了。

如果您正在查看两个位置之间的共享“所有权”,您想要的是动态分配的 shared_ptr:

#include <memory>
class Bar {
// ...
private:
  std::tr1::shared_ptr<Foo> foo;
};
于 2009-07-06T17:34:53.810 回答
4

如果成员是按包含的(不是通过指针或引用),那么您不能阻止它被删除,而且您不应该这样做。

如果您想在其他地方删除它,则使其包含在指针或引用中。

class House
{
  Door door; //contained by value, will be destroyed when the House is
}

class House
{
  Door& door; //contained by reference, will not be destroyed when the House is
}
于 2009-07-06T17:35:08.223 回答
3

析构函数中的代码只是删除动态分配的成员。成员的销毁不是可选的,您只能控制之前显式分配的内容的释放(使用 operator new)。

您可以使用 shared_ptr 获得您想要做的事情,其中​​您的类和外部代码共享一个指向同一个外部对象的指针。这样,只有当所有指向该对象的指针超出范围时,它才会被删除。但要注意不要做循环引用,shared_ptr 没有“垃圾收集器”的智慧。

当然,您可以使用这些位置共享的常规指针,但在大多数情况下,这是一个坏主意,很容易让您在以后对适当的资源释放感到头疼。

于 2009-07-06T17:37:34.567 回答
2

首先,如果成员对象是按值包含的,那么当容器对象被销毁时,它就会超出范围,并且您无法阻止它被自动释放。

相反,如果它被您的容器对象间接引用(例如使用指针),您不必特别执行任何操作来删除它。除非您明确编写代码,否则析构函数不会删除任何内容。

至于这是否不合理的问题,我认为一般来说不是,但你必须明确(通常在文档中,因为 C++ 没有语言支持这个概念)拥有相关成员的对象是什么.

于 2009-07-06T17:53:54.487 回答
1

我认为在大多数情况下,如果您不在同一个动作中破坏整个对象,您就是在自找麻烦。听起来您的类应该为该成员提供一个清理方法,该方法在析构函数中调用。如果由于某种原因必须尽快销毁该成员,则该方法可以提前返回。

于 2009-07-06T17:35:01.640 回答
0

首先,这完全不合理吗?

我不会说不合理,也许是有问题的。

一个类拥有它是完全有效的,因此应该注意清理,同时在另一个类中拥有指向该对象的引用或指针。

但是,第二个类是否应该具有该指针可能是有问题的,我宁愿在需要时始终使用 get 方法来检索该指针,例如通过调用父类或某些资源管理器。

于 2009-07-06T17:36:38.843 回答
0

如果您已为此成员动态分配内存,则可以在销毁对象之前共享对此成员的引用并且确保该成员未在对象的析构函数中销毁。但是我认为这种做法不太合理。

于 2009-07-06T17:37:35.487 回答
0

当您谈论在析构函数中删除类成员时,您必须区分不是指针的成员和那些是指针的成员。假设您有这样的课程:


class Foo
{
public:
  Foo() {p = new int;}
 ~Foo(){}

private:
 int a;
 int *p;
};

此类有 2 个数据成员:一个整数a和一个指向整数的指针p。当析构函数被调用时,对象被销毁,这意味着它的所有成员的析构函数都被调用。即使析构函数的主体为空,也会发生这种情况。对于像整数这样的原始类型,调用它的析构函数只是意味着它占用的内存将被释放。但是,销毁指针时有一个问题:默认情况下,它指向的任何内容都不会被销毁。为此,您必须明确调用delete.

因此,在我们的示例中,a将在调用析构函数时被销毁, 也将被销毁p,但不会p指向任何对象。如果您希望释放p指向的内存,则 for 的析构函数Foo应如下所示:


~Foo() {delete p};

所以,回到你的问题,当对象的析构函数被调用时,你的类中所有不是指针的成员都将被销毁。另一方面,如果您有指针成员,则它们指向的任何内容都不会被销毁,除非您在析构函数中专门为它们调用 delete。

于 2009-07-06T17:45:08.610 回答
0

为什么没有人提到弱指针和强指针?
强指针是正常动作的智能指针。
弱指针是一个智能指针,除非所有强指针都超出范围,否则它不能删除自身。
强指针表示所有权,弱指针表示共享。
查看boost.shared_ptrboost.weak_ptr以及Loki 的 StrongPtr的实现。
还要看看RAII。如果您知道 RAII,您自己就会知道这个问题的答案。

于 2009-07-06T17:53:48.310 回答
0

这并非不合理,但应注意确保隐式处理任何托管资源的清理。

(人们通常担心的第一个托管资源是内存,但任何可能泄漏的资源——内存、文件句柄、IDispatch 指针——都应该有隐式处理清理的代码)。

对于由多个对象共享的托管资源(如果“这个对象”应该有一个指向被“那个对象”清理的东西的指针,几乎肯定是这种情况),您通常需要一个“引用计数指针”来管理对象或“弱指针”,具体取决于您的生命周期要求。

对于不共享的托管资源(尤其是那些在可能引发异常时需要正确管理的资源),那么 auto_ptr 或其他变体可能更合适。

Scott Meyers Effective C++ 书籍是学习智能指针的一个合理起点,但在实践中,您可能应该只获取一个经过审查的库,如Boost,让其他人担心得到晦涩的极端情况(例如,如果构造函数抛出一个例外?)对。

于 2009-07-06T18:20:13.250 回答
0

这是可能的,但基本上正如@dmckee 所说,这是一个所有权问题。如果是这种情况,您可以进行重新计数。IE

class A
{

RefObj* obj;
A()
{

obj = new RefObj;

}

~A()
{
 obj->ReleaseRef();
}
}


RefObj
{

int m_iRefCounter;
RefObj()
{
m_iRefCounter = 1;
}
AddRef()
{
m_iRefCounter++;
}
ReleaseRef()
{
m_iRefCounter--
if(m_iRefCounter == 0)
{
 delete this;
}
}
}

}

于 2010-11-28T13:01:37.243 回答