如何防止内存泄漏?

jus*_*wes 10 c++ pointers memory-leaks memory-management

我最近正在面试一个C++职位,我被问到如何防范创建内存泄漏.我知道我没有给出那个问题的满意答案,所以我把它扔给你们.防止内存泄漏的最佳方法是什么?

谢谢!

jal*_*alf 21

到目前为止给出的所有答案归结为:避免不得不打电话delete.

程序员必须在任何时候打电话delete,你都有潜在的内存泄漏.相反,让delete呼叫自动发生.C++保证本地对象在超出范围时调用它们的析构函数.使用该保证可确保自动删除内存分配.

最常见的是,这种技术意味着每个内存分配都应该包含在一个简单的类中,其构造函数分配必要的内存,析构函数释放它.

因为这是一种常用且广泛适用的技术,所以创建了智能指针类来减少样板代码的数量.他们的构造函数不是分配内存,而是指向已经进行的内存分配,并存储它.当智能指针超出范围时,它可以删除分配.

当然,根据用途,可能需要不同的语义.您是否只需要简单的情况,其中分配应该与包装类一样长?然后使用boost::scoped_ptr或者,如果你不能使用boost, std::auto_ptr.您是否有未知数量的对象引用分配而不知道每个对象将存在多长时间?然后参考计数boost::shared_ptr是一个很好的解决方案.

但是你不必使用智能指针.标准库容器也可以解决问题.它们在内部分配存储放入其中的对象副本所需的内存,并在删除时再次释放内存.因此用户无需调用newdelete.

这种技术有无数的变化,改变了它的责任,即创建初始内存分配,或者应该执行释放.

但它们的共同点是你的问题的答案:RAII成语:资源获取是初始化.内存分配是一种资源.当对象被初始化时应该获取资源,并且当对象被销毁时,它应该被对象释放.

使C++范围和生命周期规则为您的工作做好准备.永远不要delete在RAII对象之外调用,无论是容器类,智能指针还是单个分配的ad-hoc包装器.让对象处理分配给它的资源.

如果所有delete呼叫都自动发生,那么您无法忘记它们.然后就没有办法可以泄漏内存.

  • 请注意,这可能导致与幽默的访调员进行尴尬的面试:"你如何避免内存泄漏?" ......"避免写删除!"...... (2认同)
  • 更有理由这么说;) (2认同)

Pet*_*der 20

  1. 如果您不需要,请不要在堆上分配内存.大多数工作都可以在堆栈上完成,因此您只应在绝对需要时进行堆内存分配.

  2. 如果需要由单个其他对象拥有的堆分配对象,则使用std::auto_ptr.

  3. 使用Boost的标准容器或容器,而不是发明自己的容器.

  4. 如果您有一个由其他几个对象引用的对象,并且特别是没有一个对象,则使用其中任何一个std::tr1::shared_ptrstd::tr1::weak_ptr- 适合您的用例.

  5. 如果这些东西都不符合您的用例,那么可以使用delete.如果你最终必须手动管理内存,那么只需使用内存泄漏检测工具来确保你没有泄漏任何东西(当然,要小心).你不应该真的达到这一点.

  • @Viktor:不,很多人在不知道自己在做什么的情况下编写自己的容器.少数C++程序员能够正确编写容器的事实并不意味着绝大多数人不会因被告知停止和使用标准容器而受益. (10认同)
  • @Adrian:`unique_ptr`在当前的C++标准中不存在.@Spidey:在没有利用RAII的情况下,没有程序员可以在非平凡的C++程序中"管理自己的内存".当然,RAII不仅仅是智能指针,这一点经常被人遗忘.如果你只是说智能指针不是圣杯,那你就是对的.但是"原始"删除调用在每个级别都是错误的.理智的C++程序员"管理他们的记忆"的方式是确保对象在他们应该*时自动释放*.这与使用`shared_ptr`重新计算所有内容并不完全相同 (6认同)
  • `std :: auto_ptr`已被弃用.请改用`std :: unique_ptr`. (3认同)
  • @Spidey:你在代码中使用异常吗?通过手动配对new和delete来编写异常安全的代码几乎是不可能的. (2认同)

Sca*_*ark 8

您最好阅读RAII.


Chr*_*s H 7

用shared_ptr替换new.基本上是RAII.使代码异常安全.尽可能使用stl.如果使用引用计数指针,请确保它们不形成循环.来自boost的SCOPED_EXIT也非常有用.

  • 不挑选. (2认同)