我如何*不*删除析构函数中的成员?

时间:2009-07-06 17:30:01

标签: c++ destructor ownership-semantics

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

12 个答案:

答案 0 :(得分:15)

简短回答:你没有。

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

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

祝你好运。

答案 1 :(得分:10)

取决于“删除”的含义。如果它们不在智能指针中,并且未明确删除,则不会删除它们。仅属于该课程的成员:

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

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

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

#include <memory>
class Bar {
// ...
private:
  std::tr1::shared_ptr<Foo> foo;
};

答案 2 :(得分: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
}

答案 3 :(得分:3)

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

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

当然你可以使用这些地方共享的常规指针,但在大多数情况下这是一个坏主意,以后会让你头疼关于正确的资源释放。

答案 4 :(得分:2)

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

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

关于这是否不合理的问题,我认为通常不是这样,但你必须明确(通常在文档中,因为C ++没有语言支持这个概念)拥有有问题的成员。

答案 5 :(得分:1)

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

答案 6 :(得分:0)

  

首先,完全是这样   不合理?

我不会说不合理,也许是可疑的。

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

然而,如果第二类reall应该有那个指针可能有问题,我宁愿总是使用get-method在我需要的时候检索指针,例如通过调用父类或某个资源管理器。

答案 7 :(得分:0)

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

答案 8 :(得分:0)

当你谈到在析构函数中被删除的类成员时,你必须区分非指针的成员和那些成员。假设你有这样一个类:


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

private:
 int a;
 int *p;
};

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

因此,在我们的示例中,a将在调用析构函数时被销毁,p也将被销毁,但p指向的不是p。如果您希望释放Foo点的内存, ~Foo() {delete p}; 的析构函数应如下所示:

{{1}}

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

答案 9 :(得分:0)

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

答案 10 :(得分:0)

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

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

对于由多个对象共享的托管资源(几乎可以肯定的是,如果“此对象”应该具有指向“该对象”清理的内容的指针),则通常需要“引用计数指针”管理对象或“弱指针”,具体取决于您的生命周期要求。

对于未共享的托管资源(特别是那些在抛出异常时需要正确管理的资源),auto_ptr或其他变体可能更合适。

Scott Meyers有效的C ++书籍是学习智能指针的合理起点,但在实践中你应该只是抓住像Boost这样的审查库,让其他人担心得到模糊的角落案例(如如果构造函数抛出异常会发生什么?)正确。

答案 11 :(得分:0)

这是可能的,但基本上@dmckee说这是一个所有权问题。如果是这种情况可能是你可以去refcounting。即。

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;
}
}
}

}