手机站
网通分站
电信主站
密 码:
用户名:
当前位置 : 主页>程序设计>C/C++>列表

Bjarne:如何对付内存泄漏?

来源:互联网 作者:west263.com 时间:2008-02-23
西部数码-全国虚拟主机10强!40余项虚拟主机管理功能,全国领先!双线多线虚拟主机南北访问畅通无阻!免费赠送企业邮局,.CN域名,自助建站480元起,免费试用7天,满意再付款! P4主机租用799元/月.月付免压金!
 写出那些不会导致任何内存泄漏的代码。很明显,当您的代码中到处充满了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)。



文章整理:西部数码--专业提供域名注册虚拟主机服务
http://www.west263.com
以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

热点关注
IDC资讯 虚拟主机 域名注册 托管租用 vps主机 智能建站
网站运营 建站经验 策划盈利 搜索优化 网站推广 免费资源
网站联盟 联盟新闻 联盟介绍 联盟点评 网赚技巧
行业资讯 业界动态 搜索引擎 网络游戏 门户动态 电子商务 广告传媒
网络编程 Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术 Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷 Internet Explorer
网页制作 FrontPages Dreamweaver Javascript css photoshop fireworks Flash
程序设计 Java技术 C/C++ VB delphi
网络知识 网络协议 网络安全 网络管理 组网方案 Cisco技术
操作系统 Win2000 WinXP Win2003 Mac OS Linux FreeBSD
返回首页 |关于我们 | 联系我们 | 付款方式 | 创业联盟 | 价格总览 | 资讯中心 | 友情链接 | 网站地图 | 招贤纳士 | RSS