如何使智能指针在exit()时超出范围
Posted
技术标签:
【中文标题】如何使智能指针在exit()时超出范围【英文标题】:how to make smart pointer go out of scope at exit() 【发布时间】:2012-07-30 19:49:56 【问题描述】:我花了一些时间编写一个应用程序来练习,并且我喜欢在整个过程中使用智能指针,以避免在我忘记删除某些内容时发生内存泄漏。同时,我也喜欢使用异常来报告构造函数中的失败并尝试处理它。但是,当它不能时,我希望它通过调用 assert() 或 exit() 退出该位置的程序。但是,在 msvc 中使用 crtdbg 库时,它会报告来自智能指针的内存泄漏,该智能指针具有动态分配给它们的任何内容。这对我来说意味着两件事之一。 1) 智能指针永远不会超出分配它们的范围,也永远不会释放,从而导致一些内存泄漏,或者 2) crtdbg 没有捕获释放,因为它没有在 main 处退出。不过,从this 页面,使用 _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );在程序开始时将捕获任何退出点的泄漏,我仍然使用它得到内存泄漏错误。
所以我向你们提出的问题是,内存实际上会在退出或断言时被释放吗?如果没有,我是否能够从 std::shared_ptr 派生并实现我自己的解决方案来编目要释放的动态分配的对象在调用退出或断言之前,或者对于更简单的解决方案来说工作量太大?
【问题讨论】:
如果进程死了,你为什么还要关心释放? 如果调用exit
,堆栈不会展开,局部变量不会被破坏。但是,尚不清楚您要完成什么:如果您希望销毁局部变量,请在main()
中抛出异常和catch (...)
以确保堆栈已展开。
@尤里·基洛切克:好问题。有关系吗?当我看到内存泄漏错误时,我很担心,但是如果进程退出,那我还需要担心吗?
@FatalCatharsis 你不知道。操作系统释放进程在执行期间获取的所有资源。但是,您可能希望保留一些外部状态,例如在终止之前将一些缓冲区转储到文件中。
@ yuri Kilochek:那么我想这就是我的问题的答案,忽略它,它就会消失:P。非常感谢
【参考方案1】:
当程序退出时,内存无论如何都会被操作系统回收,所以如果泄漏让你担心,它不应该。
但是,如果您的析构函数中有逻辑,并且必须销毁对象 - 调用 exit
显式绕过所有释放。解决方法是在调用 exit 的地方抛出异常,在 main
中捕获它并返回。
#include "stdlib.h"
void foo()
//exit(0);
throw killException();
int main
try
foo();
catch (killException& ex)
//exit program calling destructors
return EXIT_FAILURE;
【讨论】:
第一句话就是我所需要的,内存泄漏错误让我相信我这样做的方式有什么可怕的错误,但我想只是退出程序会释放所有资源,所以它没关系:\。谢谢一堆。会接受的时候我可以 @FatalCatharsis:你这样做的方式is有问题,不管内存是否真的泄漏了:) @DavidRodríguez-dribeas:多个出口点真的那么糟糕吗?我在处理构造函数中的异常后退出,因为如果失败,那么使用该对象是不安全的。如果您在抛出异常后尝试使用该对象,则会出现错误。我宁愿在构造函数中处理并退出,然后将其传播给外部用户处理,因为这样他们就可以继续程序并继续使用它。在这种情况下,您还有什么建议? @FatalCatharsis:构造函数应该失败并出现异常,但这并不意味着整个应用程序应该死掉。一些更高级别的代码可能能够处理这个问题。更高级别的逻辑应该有机会从错误状态中恢复。【参考方案2】:真正的问题不在于内存,而在于其他资源。操作系统将(在大多数情况下,除非您正在运行嵌入式系统)在进程终止时从进程中恢复内存,因此内存不会在操作系统中泄漏。实际问题可能出在您的流程之外的其他资源,可能需要在您的流程完成之前释放...
无论如何,为什么您更喜欢abort
或exit
而不是让异常传播?一般来说,您应该只处理您想要管理的异常并让其他异常通过。虽然您可能无法从中恢复,但您的呼叫者实际上可能能够恢复。通过捕获异常并当场退出程序,您将取消用户的处理选择。
【讨论】:
以上是关于如何使智能指针在exit()时超出范围的主要内容,如果未能解决你的问题,请参考以下文章