c – 我什么时候应该为我班级提供一个析构函数?

前端之家收集整理的这篇文章主要介绍了c – 我什么时候应该为我班级提供一个析构函数?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
这似乎是一个相当微不足道或至少是常见的问题,但我无法在谷歌或SO上找到令人满意的答案.

我不确定何时应该为我的班级实现析构函数.

一个明显的例子是当类包装到文件的连接时,我想确保连接已关闭,所以我在析构函数关闭它.

但是我想知道一般,我怎么知道我是否应该定义一个析构函数.我可以检查哪些指南,看看我是否应该在这个类中有一个析构函数

我能想到的一个这样的指导原则是,该类是否包含任何成员指针.默认的析构函数删除指针,但不会指向它们指向的对象.所以这应该是用户定义的析构函数的工作.例如:(我是C新手,所以这段代码可能无法编译).

class MyContainer {
public:
    MyContainer(int size) : data(new int[size]) { }
    ~MyContainer(){
        delete [] data;
    }
    // .. stuff omitted
private:
    int* data;
}

如果我没有提供析构函数,那么销毁MyContainer对象就意味着创建泄漏,因为之前由数据引用的所有数据都不会被删除.

但我有两个问题:

1-这是唯一的“指南”吗?即如果类有成员指针或者它正在管理资源,那么定义一个析构函数?还是还有别的吗?

2-是否有不应删除成员指针的情况?参考怎么样?

解决方法

如果默认销毁不够,则需要定义析构函数.当然,这只会引发一个问题:默认析构函数有什么作用?好吧,它调用每个成员变量的析构函数,就是这样.如果这对你来说已经足够了,那么你很高兴.如果不是,那么你需要编写一个析构函数.

最常见的示例是使用new分配指针的情况.指针(对任何类型)都是一个基元,析构函数只是让指针本身消失,而不会触及指向内存的指针.所以指针的默认析构函数对我们没有正确的行为(它会泄漏内存),因此我们需要在析构函数中进行删除调用.想象一下,现在我们将原始指针更改为智能指针.当智能指针被销毁时,它还会调用其指向的析构函数,然后释放内存.所以智能指针的析构函数就足够了.

通过了解最常见案例背后的根本原因,您可以推断不太常见的案例.通常,如果你使用智能指针和std库容器,它们的析构函数会做正确的事情而你根本不需要编写析构函数.但仍有例外.

假设您有一个Logger类.这个记录器类很聪明,它将一堆消息缓冲到Log,然后只有当缓冲区达到一定大小时才将它们写入文件(它“刷新”缓冲区).这可能比仅将所有内容立即转储到文件更具性能.当Logger被销毁时,你需要从缓冲区中清除所有内容,无论它是否已满,所以你可能想为它编写一个析构函数,即使它很容易根据std :: vector和std实现Logger. :: string,以便在销毁时没有任何泄漏.

编辑:我没有看到问题2.问题2的答案是,如果它是非拥有指针,则不应调用delete.换句话说,如果某个其他类或范围单独负责在此对象之后进行清理,并且您的指针“只是为了查看”,则不要调用delete.原因是如果你调用delete而其他人拥有它,指针会被调用两次:

struct A {
  A(SomeObj * obj) : m_obj(obj){};
  SomeObj * m_obj;
  ~A(){delete m_obj;};
}

SomeObj * obj = new SomeObj();
A a(obj);
delete obj; // bad!

实际上,可以说c 11中的指南是永远不要在指针上调用delete.为什么?好吧,如果你在指针上调用delete,就意味着你拥有它.如果您拥有它,则没有理由不使用智能指针,特别是unique_ptr实际上是相同的速度并自动执行此操作,并且更可能是线程安全的.

此外,(请原谅我,我现在已经真正了解这一点),对其他对象的对象(原始指针或引用)成员进行非拥有视图通常是个坏主意.为什么?因为具有原始指针的对象可能不必担心破坏另一个对象,因为它不拥有它,但它无法知道它何时会被销毁.当指针对象仍处于活动状态时,指向的对象可能会被销毁:

struct A {
  SomeObj * m_obj;
  void func(){m_obj->doStuff();};
}

A a;
if(blah) {
  SomeObj b;
  a.m_obj = &b;
}
a.func() // bad!

请注意,这仅适用于对象的成员字段.将对象的视图传递给函数(成员与否)是安全的,因为函数是在对象本身的封闭范围内调用的,因此这不是问题.

所有这些的苛刻结论是,除非你知道你在做什么,否则你不应该将原始指针或引用作为对象的成员字段.

编辑2:我猜总体结论(非常好!)一般来说,你的类应该以不需要析构函数的方式编写,除非析构函数在语义上有意义.在我的Logger示例中,必须刷新Logger,在销毁之前必须执行一些重要操作.您不应该编写(通常)需要在其成员之后进行简单清理的类,成员变量应该自行清理.

猜你在找的C&C++相关文章