我最近参加了一次 C++ 职位的面试,被问到如何防止内存泄漏。我知道我的回答并不令人满意,所以我把这个问题留给你们了。有哪些最好的方法可以防止内存泄漏呢?
谢谢!
我最近参加了一次 C++ 职位的面试,被问到如何防止内存泄漏。我知道我的回答并不令人满意,所以我把这个问题留给你们了。有哪些最好的方法可以防止内存泄漏呢?
谢谢!
delete
。任何时候程序员必须调用delete
,都可能导致内存泄漏。相反,让delete
调用自动发生。C++保证本地对象在超出其范围时调用其析构函数。利用这种保证来确保您的内存分配被自动删除。最常见和广泛适用的技术是,将每个内存分配包装在一个简单的类中,其构造函数分配所需的内存,析构函数释放它。智能指针类已经创建,以减少样板代码的数量。它们的构造函数不是分配内存,而是采用对已经进行的内存分配的指针并存储该指针。当智能指针超出范围时,它能够删除分配。标准库容器也可以做到这一点。它们内部分配了存储放入其中对象的副本所需的内存,并在删除它们时释放内存。因此,用户无需调用new
或delete
。这种技术有无数变化形式,改变了谁来创建初始内存分配,或者何时执行解除分配。但它们共同回答了您的问题:RAII范式:资源获取即初始化。内存分配是一种资源。资源应在对象初始化时获取,并在对象本身被销毁时释放。让C++的作用域和生命周期规则为您服务。永远不要在RAII对象之外调用delete
,无论它是一个容器类、智能指针还是某个单独分配内存的临时包装器。让对象处理其所分配的资源。
如果所有的delete
调用都是自动发生的,那么您就不可能忘记它们。这样就没有内存泄漏的风险了。
scoped_ptr
删除它所指向的对象。引用计数(和shared_ptr
)是RAII的一个特例,并且它具有一些关键性缺陷,而且被过度使用了。但这并没有改变我所说的,即RAII 总体上是避免泄漏的方法。 - jalf如果没有必要,不要在堆上分配内存。大多数工作都可以在栈上完成,因此只有在绝对需要时才应进行堆内存分配。
如果需要一个由单个其他对象拥有的堆分配对象,则使用std :: auto_ptr
。
使用标准容器或Boost中的容器,而不是自己发明。
如果您有一个被多个其他对象引用且没有特定所有者的对象,则使用std :: tr1 :: shared_ptr
或std :: tr1 :: weak_ptr
- 适合您的用例。
如果以上这些情况都不适用于您的用例,则可能使用delete
。如果最终确实需要手动管理内存,请使用内存泄漏检测工具确保您没有泄漏任何内容(当然,一定要小心)。但您不应该真正走到这一步。
std::auto_ptr
已被弃用,请使用 std::unique_ptr
。 - Adrian McCarthyunique_ptr
在当前的C++标准中并不存在。
@Spidey:在一个非平凡的C++程序中,没有程序员能够"管理自己的内存",除非利用RAII。当然,RAII远不止是智能指针,这一点经常被忽略。如果你仅仅是指智能指针不是万能的,那么你是正确的。但是,在任何情况下都不应该使用“裸”的delete调用。理智的C++程序员“管理他们的内存”的方法是确保对象在它们应该被释放的时候自动释放。这与使用shared_ptr
使所有东西引用计数并不完全相同。 - jalf使用shared_ptr替换new操作,基本上是RAII(资源获取即初始化)的应用。这样可以使代码具有异常安全性。尽可能地在代码中使用STL。如果您使用引用计数指针,请确保它们不会形成循环。来自boost的SCOPED_EXIT也非常有用。
(简单) 永远不要让一个裸指针拥有一个对象(在你的代码中搜索正则表达式"\= *new"
)。使用shared_ptr或scoped_ptr代替,甚至更好的做法是尽可能使用真实变量而不是指针。
(困难) 确保没有循环引用,即共享指针相互引用的情况,使用weak_ptr来打破它们。
完成!
使用各种智能指针。
采用特定的对象创建和删除策略,例如谁创建了对象就应该负责删除它。
除了RAII的建议外,如果有任何虚函数,请记得将基类析构函数声明为虚函数。