单例类的析构函数

4

问题:如果一个单例类具有程序范围(在程序启动时出现并在程序结束时死亡),我应该编写析构函数吗?

详情:

我在犹豫中:

"我是否应该为单例类编写析构函数?"

1)此类具有程序范围
2)类在堆上使用了大量内存,因此释放内存需要时间

当用户退出程序时,响应应该很快,所以为什么要花时间释放由此单例占用的内存,因为内存将在程序结束时释放。


"快速"在“响应应该快速”中的意思是什么? - David Rodríguez - dribeas
@dribeas:也许是进程间通信中wait()调用的快速响应? - P Shved
6个回答

3
如果释放内存需要很长时间,那就不要这样做。这可能是一个耗时的问题,特别是如果释放内存导致大量缓存未命中。操作系统会处理这个问题(当然,如果您正在运行实际执行此操作的系统)。
但是,如果您的析构函数对某些资源进行了最终化处理(例如,解锁文件或硬件),并且您使用“资源获取即初始化”,则必须确保调用了正确的析构函数(例如,在您的main()函数返回后调用静态对象的析构函数)。如果一些在单例中分配的对象也锁定资源,则也适用于此!因此,在大多数情况下,最好实际上编写此类对象的析构函数,并使其可选地释放内存。
提问者SSS决定根本不编写析构函数。但是,我想再争论一下,这并不是最佳解决方案。
不释放静态对象的内存(让我们称之为“静态”)是一种非常微妙的优化,与常识和人们通常编写程序的方式相矛盾。您的代码分配内存并仅仅没有析构函数,看起来很奇怪。同事们会认为这个类编写得很差,并倾向于在其中查找错误(而它们实际上在另一个类中)。
相反,您应该遵循通用编码标准,这些标准规定C++中的内存管理应该是正确的。确实编写析构函数,并仅在它显示具有显著提升不进行释放时,才将代码包装起来以使其不被调用。
不释放内存的意图必须是明确的。
MySingleton::~MySingleton()
{
#ifndef RELEASE
  // The memory will be released by OS when program terminates!
  delete ptr1;
  delete ptr2;
#endif
}

甚至更多。
MySingleton::~MySingleton()
{
  // We don't do anything here.
  // The memory will be released by OS when program terminates!
}

但是析构函数更好地保持了持久性。


你是对的: a) 析构函数需要很长时间来删除所有层次结构 b) 它是单线程的,不承担任何资源的最终化责任因此,我决定不编写任何析构函数,以便在关闭应用程序时获得更好的使用体验。 - Satbir
亲爱的Pavel,我尊重你的想法,我同意这看起来很奇怪。我已经遵循了“明确不释放内存的意图”的想法,也会收到有关内存泄漏的警告。但是我在我的2GhZ CPU上看到了约300毫秒的提升,在主机器上(该机器具有Xenon处理器)将会更少。 - Satbir

2
听起来你正在创建一个上帝对象,因此重新考虑你的类的设计可能会有益处。
是否添加析构函数取决于是否值得为了释放并最终重新分配内存而付出性能代价。

1
如果SSS相信上帝,为什么我们不信呢?;-) - P Shved
1
我绝对不是在说这样做行不通——只是想要为他或者那些将来会维护这个应用程序的人节省一些麻烦。 - Justin Rusbatch

2

C++语言不能保证程序终止时内存会被回收,但是任何一个像样的操作系统都可以轻松完成这个任务。

所以,如果:

  • 你正在运行一个像样的操作系统,且
  • 析构函数除了释放内存之外没有其他事情要做

那么,你可以省略析构函数,泄漏内存,并依靠操作系统在你之后清理它。

显然,这样做的明显缺点是各种调试工具可能会大声疾呼地指出内存泄漏问题。

当然,一个稍微更基本的问题是:为什么要创建一个分配如此大的内存的单例?

我认为这听起来是可怕的设计。


我同意这是一个糟糕的设计,但系统非常稳定...我不会得到更改设计的许可 :)... - Satbir

2
实现析构函数是正确的方式,也是最可维护的版本。然后测量(创建一个只创建单例并退出的可执行文件)释放内存所需的实际时间。
当你有了硬性事实,即正确删除的成本,不要编写错误的代码。如果它需要一些可测量的时间,请将其视为相对于程序运行时间的相对度量。在大多数情况下,应用程序所需的处理将比释放内存所需的时间多得多。
如果你仍然认为它需要太多时间,请考虑常规用户会认为需要多少时间,应用程序被打开和关闭的次数,以及它是否真正重要。
如果最终你认为它太耗时了,那么你面临的风险是在稍后的时间里可能会修改应用程序,单例可能会获取外部资源而不释放它们--这在文件锁定方面特别糟糕...。
牺牲正确性以换取性能的人都不值得拥有它们。

0
如果您正在运行Windows操作系统,则任何进程占用的所有内存/资源都将在应用程序关闭时被回收,因此在我看来这并不重要。

2
从技术上讲,所有操作系统都应该可以胜任,但我要指出的是,Windows 是我见过使用时间最长的最有 bug 的内存管理器。我曾经看到它在这些任务上失败过,尽管在较新的 Windows 版本中情况没有那么糟糕。 - ewanm89
2
也许你可以用一些事实来支持你的说法?举一个Windows(2000及以上版本)无法回收内存的情况的例子。否则你只是在传播自己的无知。 - jalf

-2
正如所指出的那样,操作系统应该在结束时释放内存,但是你真的想信任它来管理吗?至少通过显式销毁,一个有缺陷/设计不良的内存管理器有更大的机会做到正确。

这样它就有两次机会去做对。


假设您的操作系统支持,您可以完全依赖操作系统内存管理器来彻底销毁进程的虚拟地址空间。这发生在不同的概念层面上,而不是C++自由存储器释放。 - TheFogger
我见过一些内存管理器在执行此任务时失败的例子。这取决于各种因素,理论上是可以工作的。请记住,内核内存管理器也要担心它是否是多个进程之间共享的内存等问题。在某些情况下,错误可能会导致它们错误地处理内存。 - ewanm89
我是说,如果一个人已经在管理内存,那么他就不太依赖可能会出问题的内核了。 - ewanm89
如果您的内核损坏了,对于您和客户来说,进程中的泄漏问题仅是最小的担忧。选择另一个平台或准备好过上地狱般的生活。 - Integer Poet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接