最近我正在使用C ++学习OOP,在以下情况下我应该使用自己的销毁功能时我很困惑:
class T1{
private:
int data;
public:
T1(){...};
~T1(){}; // should I write my own function here?
};
class T2{
private:
T1* pointer_to_T1;
public:
T2(){...};
~T2(){}; // should I write my own function here?
};
class Node{
public:
int data;
Node* next;
};
class T3{
private:
int size;
Node* head;
public:
T3(size){
head = new Node[size];
}
~T3(){}; // should I write my own function here?
};
我的计划中有三条评论可以澄清我的问题。我希望你能解释一下,如果你能给我一个一般规则,我将不胜感激。
答案 0 :(得分:1)
如果class T3
正在分配新内存,那么您必须在destructure中删除已分配的内存段。
class T3{
private:
int size;
Node* head;
public:
T3(size){
head = new Node[size];
}
~T3(){
delete[] head;
};
};
答案 1 :(得分:0)
类的析构函数应该执行删除对象时所需的所有操作。
例如,它需要释放由类动态分配的所有内存。
答案 2 :(得分:0)
当您的类是基类时,您应该编写析构函数,并且您希望在对象被销毁时运行多态破坏。
如果对象拥有并管理资源,您可能需要一个构造函数。不要忘记复制和赋值操作符。
答案 3 :(得分:0)
对象应该自行清理。
IE,如果您在对象中分配内存,可能在构造函数中完成,那么您应该在析构函数中释放该内存。
析构函数用于在对象之后进行清理。所以你也可以做任何事情来帮助你做到这一点。
答案 4 :(得分:0)
类T1不需要明确定义析构函数。将编译器隐式定义析构函数就足够了。
类T2需要显式定义析构函数,以释放其具有类型指针的数据成员。否则会有内存泄漏。
类节点不需要显式定义析构函数。 T3类必须删除Node类的所有指针,因为它控制着节点的分配和释放。
答案 5 :(得分:0)
你需要声明一个析构函数:
在第一种情况下,您还需要提供或删除复制构造函数和复制赋值运算符;否则你最终可能会遇到两个或多个试图管理相同资源的对象。这被称为"Rule of Three"。通常,您可以使用现成的类(如容器和智能指针)来为您管理内存;因此,通常不需要自己使用析构函数。有人将此称为“零度规则”。
在第二种情况下,析构函数不必做任何事情(假设类没有尝试管理任何资源),它只需要是虚拟的。
针对您的具体示例:
T1
不需要析构函数T2
可能,取决于它是否应该管理指针指向的任何内容。如果是,则考虑用智能指针替换指针,如std::unique_ptr<T1>
。T3
可能会这样做,因为它似乎在管理动态数组。你还需要考虑三法则;或者考虑使用std::vector<Node>
自动管理阵列。答案 6 :(得分:0)
我会尝试以一般方式回答您的代码段不具体。
通常会出现两种常见情况,您需要使用非平凡的析构函数。这不是一个完整的列表;只是最常见的情况。
1)在(多态)层次结构中。如果您的类是一个基类,意图从中派生,那么您的基类很可能具有非平凡的析构函数。而且,析构函数可能应该是virtual
。这使得可以通过基类指针删除派生类对象,如下所示:
class Foo
{
public:
virtual ~Foo(){}
};
class Bar : public Foo
{
};
int main()
{
Foo* obj = new Bar;
delete obj;
}
如果没有virtual
析构函数,此程序将显示未定义的行为。
2)当你的班级成员需要的不仅仅是琐碎的破坏。一个简单的例子就是你的类有一个成员,它是一个原始指针(如不是智能指针),是使用new
。该指针需要delete
d,析构函数可能是正确的位置。如果您的类具有复制构造函数或复制赋值运算符(operator=
),则表明您的类管理非平凡可破坏成员的良好迹象。如果你的类有任何一个,那么它可能需要它们 plus 一个析构函数来处理分配的内容。 (参见Rule of Three)这不是唯一的指示 - 你可能只有一个默认的构造函数,但仍然需要一个析构函数。这取决于你班级的作用。