搜索文章:

首页  |  Java技术  |  Asp.net  |  Asp编程  |  VC/C++  |  Delphi  |  VB编程

全文阅读

天极软件专题专区精选     到天极软件“读编交流区”畅所欲言
Google专区 POPO专区 QQ专区 QQ挂机 了解Web2.0
Flash MX 视频教程 Photoshop视频教程 网页设计视频教程 照片处理数字暗房
PPT动画演示教程 Excel动画教程集 Word动画演示教程 Windows Vista专区
特洛伊木马专区 黑客知识教程专区 防火墙应用专区 注册表应用专区
Windows API开发专区 网络编程专区 VB数据库编程专区 图像处理与多媒体编程

  写出那些不会导致任何内存泄漏的代码。很明显,当你的代码中到处充满了new 操作、delete操作和指针运算的话,你将会在某个地方搞晕了头,导致内存泄漏,指针引用错误,以及诸如此类的问题。这和你如何小心地对待内存分配工作其实完全没有关系:代码的复杂性最终总是会超过你能够付出的时间和努力。于是随后产生了一些成功的技巧,它们依赖于将内存分配(allocations)与重新分配(deallocation)工作隐藏在易于管理的类型之后。标准容器(standard containers)是一个优秀的例子。它们不是通过你而是自己为元素管理内存,从而避免了产生糟糕的结果。想象一下,没有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’;
}

  你有多少机会在第一次就得到正确的结果?你又怎么知道你没有导致内存泄漏呢?

  注意,没有出现显式的内存管理,宏,造型,溢出检查,显式的长度限制,以及指针。通过使用函数对象和标准算法(standard algorithm),我可以避免使用指针——例如使用迭代子(iterator),不过对于一个这么小的程序来说有点小题大作了。

  这些技巧并不完美,要系统化地使用它们也并不总是那么容易。但是,应用它们产生了惊人的差异,而且通过减少显式的内存分配与重新分配的次数,你甚至可以使余下的例子更加容易被跟踪。早在1981年,我就指出,通过将我必须显式地跟踪的对象的数量从几万个减少到几打,为了使程序正确运行而付出的努力从可怕的苦工,变成了应付一些可管理的对象,甚至更加简单了。

  如果你的程序还没有包含将显式内存管理减少到最小限度的库,那么要让你程序完成和正确运行的话,最快的途径也许就是先建立一个这样的库。

  模板和标准库实现了容器、资源句柄以及诸如此类的东西,更早的使用甚至在多年以前。异常的使用使之更加完善。

  如果你实在不能将内存分配/重新分配的操作隐藏到你需要的对象中时,你可以使用资源句柄(resource handle),以将内存泄漏的可能性降至最低。这里有个例子:我需要通过一个函数,在空闲内存中建立一个对象并返回它。这时候可能忘记释放这个对象。毕竟,我们不能说,仅仅关注当这个指针要被释放的时候,谁将负责去做。使用资源句柄,这里用了标准库中的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; // 谁该负责释放这个S?
};

auto_ptr<S> g()
{
 return auto_ptr<S>(new S); // 显式传递负责释放这个S
}

int main()
{
 cout << "start main\n";
 S* p = f();
 cout << "after f() before g()\n";
 // S* q = g(); // 将被编译器捕捉
 auto_ptr<S> q = g();
 cout << "exit main\n";
 // *p产生了内存泄漏
 // *q被自动释放
}

  在更一般的意义上考虑资源,而不仅仅是内存。

  如果在你的环境中不能系统地应用这些技巧(例如,你必须使用别的地方的代码,或者你的程序的另一部分简直是原始人类(译注:原文是Neanderthals,尼安德特人,旧石器时代广泛分布在欧洲的猿人)写的,如此等等),那么注意使用一个内存泄漏检测器作为开发过程的一部分,或者插入一个垃圾收集器(garbage collector)。


下一篇:全文阅读 >>
相关文章:
© 2006   www.java-asp.net