荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: Dreamer (我与萤火虫), 信区: SoftDev
标  题: 【C++】[FAQ]我应该怎样处理内存泄漏?
发信站: 荔园晨风BBS站 (Fri Jun 11 12:38:44 2004), 站内信件


Q: 我应该怎样处理内存泄漏?
A: 很简单,只要写“不漏”的代码就完事了啊。显然,如果你的代码到处是new、
delete、指针运算,那你想让它“不漏”都难。不管你有多么小心谨慎,君为人,
非神也,错误在所难免。最终你会被自己越来越复杂的代码逼疯的——你将投身于
与内存泄漏的奋斗之中,对bug们不离不弃,直至山峰没有棱角,地球不再转动。
而能让你避免这样困境的技巧也不复杂:你只要倚重隐含在幕后的分配机制——构
造和析构,让C++的强大的类系统来助你一臂之力就OK了。标准库中的那些容器就
是很好的实例。它们让你不必化费大量的时间精力也能轻松惬意地管理内存。我们
来看看下面的示例代码——设想一下,如果没有了string和vector,世界将会怎样
?如果不用它们,你能第一次就写出毫无内存错误的同样功能代码吗?
#include<vector>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;

int main() // small program messing around with strings
{
cout << "enter some whitespace-separated words:\n";
vector<string> v;
string s;
while (cin>>s) v.push_back(s);

sort(v.begin(),v.end());

string cat;
typedef vector<string>::const_iterator Iter;
for (Iter p = v.begin(); p!=v.end(); ++p) cat += *p+"+";
cout << cat << '\n';
}

请注意这里没有显式的内存管理代码。没有宏,没有类型转换,没有溢出检测,没
有强制的大小限制,也没有指针。如果使用function object和标准算法[译注:指
标准库中提供的泛型算法],我连Iterator也可以不用。不过这毕竟只是一个小程
序,杀鸡焉用牛刀?

当然,这些方法也并非无懈可击,而且说起来容易做起来难,要系统地使用它们也
并不总是很简单。不过,无论如何,它们的广泛适用性令人惊讶,而且通过移去大
量的显式内存分配/释放代码,它们确实增强了代码的可读性和可管理性。早在
1981年,我就指出通过大幅度减少需要显式加以管理的对象数量,使用C++“将事
情做对”将不再是一件极其费神的艰巨任务。

如果你的应用领域没有能在内存管理方面助你一臂之力的类库,那么如果你还想让
你的软件开发变得既快捷又能轻松得到正确结果,最好是先建立这样一个库。

如果你无法让内存分配和释放成为对象的“自然行为”,那么至少你可以通过使用
资源句柄来尽量避免内存泄漏。这里是一个示例:假设你需要从函数返回一个对象
,这个对象是在自由内存堆上分配的;你可能会忘记释放那个对象——毕竟我们无
法通过检查指针来确定其指向的对象是否需要被释放,我们也无法得知谁应该负责
释放它。那么,就用资源句柄吧。比如,标准库中的auto_ptr就可以帮助澄清:“
释放对象”责任究竟在谁。我们来看:

#include<memory>
#include<iostream>
using namespace std;

struct S {
S() { cout << "make an S\n"; }
~S() { cout << "destroy an S\n"; }
S(const S&) { cout << "copy initialize an S\n"; }
S& operator=(const S&) { cout << "copy assign an S\n"; }
};

S* f()
{
return new S; // who is responsible for deleting this S?
};

auto_ptr<S> g()
{
return auto_ptr<S>(new S); // explicitly transfer responsibility for
deleting this S
}

int main()
{
cout << "start main\n";
S* p = f();
cout << "after f() before g()\n";
// S* q = g(); // caught by compiler
auto_ptr<S> q = g();
cout << "exit main\n";
// leaks *p
// implicitly deletes *q
}

这里只是内存资源管理的例子;至于其它类型的资源管理,可以如法炮制。

如果在你的开发环境中无法系统地使用这种方法(比方说,你使用了第三方提供的
古董代码,或者远古“穴居人”参与了你的项目开发),那么你在开发过程中可千
万要记住使用内存防漏检测程序,或者干脆使用垃圾收集器(Garbage Collector
)。




--
如果你真的爱萤火虫,你就不应该将她困在瓶子里;
如果你真的爱萤火虫,你应该放开她,让她在天空中自由自在地飞!
虽然你会不舍得她,但是最终你就会明白这样你才真正拥有了她!

※ 来源:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.223]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店