C++中的废料收集

2016-01-29 12:23 1 1 收藏

C++中的废料收集,C++中的废料收集

【 tulaoshi.com - C语言心得技巧 】

C++中的废料收集
作者:死猫

提交者:eastvc 发布日期:2003-9-20 10:01:25
原文出处:http://www.cpphelp.net/issue/gc.html


Java的爱好者们经常批评C++中没有提供与Java类似的废料收集(Gabage Collector)机制(这很正常,正如C++的爱好者有时也攻击Java没有这个没有那个,或者这个不行那个不够好),导致C++中对动态存储的官吏称为程序员的噩梦,不是吗?你经常听到的是内存遗失(memory leak)和非法指针存取,这一定令你很头疼,而且你又不能抛弃指针带来的灵活性。

在本文中,我并不想揭露Java提供的废料收集机制的天生缺陷,而是指出了C++中引入废料收集的可行性。请读者注意,这里介绍的方法更多的是基于当前标准和库设计的角度,而不是要求修改语言定义或者扩展编译器。

1 什么是废料收集?

作为支持指针的编程语言,C++将动态管理存储器资源的便利性交给了程序员。在使用指针形式的对象时(请注意,由于引用在初始化后不能更改引用目标的语言机制的限制,多态性应用大多数情况下依赖于指针进行),程序员必须自己完成存储器的分配、使用和释放,语言本身在此过程中不能提供任何帮助,也许除了按照你的要求正确的和操作系统亲密合作,完成实际的存储器管理。标准文本中,多次提到了“未定义(undefined)”,而这大多数情况下和指针相关。

某些语言提供了废料收集机制,也就是说程序员仅负责分配存储器和使用,而由语言本身负责释放不再使用的存储器,这样程序员就从讨厌的存储器管理的工作中脱身了。然而C++并没有提供类似的机制,C++的设计者Bjarne Stroustrup在我所知的唯一一本介绍语言设计的思想和哲学的著作《The Design and Evolution of C++》(中译本:C++语言的设计和演化)中花了一个小节讨论这个特性。简而言之,Bjarne本人认为,

“我有意这样设计C++,使它不依赖于自动废料收集(通常就直接说废料收集)。这是基于自己对废料收集系统的经验,我很害怕那种严重的空间和时间开销,也害怕由于实现和移植废料收集系统而带来的复杂性。还有,废料收集将使C++不适合做许多底层的工作,而这却正是它的一个设计目标。但我喜欢废料收集的思想,它是一种机制,能够简化设计、排除掉许多产生错误的根源。

需要废料收集的基本理由是很容易理解的:用户的使用方便以及比用户提供的存储管理模式更可靠。而反对废料收集的理由也有很多,但都不是最根本的,而是关于实现和效率方面的。

已经有充分多的论据可以反驳:每个应用在有了废料收集之后会做的更好些。类似的,也有充分的论据可以反对:没有应用可能因为有了废料收集而做得更好。

并不是每个程序都需要永远无休止的运行下去;并不是所有的代码都是基础性的库代码;对于许多应用而言,出现一点存储流失是可以接受的;许多应用可以管理自己的存储,而不需要废料收集或者其他与之相关的技术,如引用计数等。

我的结论是,从原则上和可行性上说,废料收集都是需要的。但是对今天的用户以及普遍的使用和硬件而言,我们还无法承受将C++的语义和它的基本库定义在废料收集系统之上的负担。”

以我之见,统一的自动废料收集系统无法适用于各种不同的应用环境,而又不至于导致实现上的负担。稍后我将设计一个针对特定类型的可选的废料收集器,可以很明显地看到,或多或少总是存在一些效率上的开销,如果强迫C++用户必须接受这一点,也许是不可取的。

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com)

关于为什么C++没有废料收集以及可能的在C++中为此做出的努力,上面提到的著作是我所看过的对这个问题叙述的最全面的,尽管只有短短的一个小节的内容,但是已经涵盖了很多内容,这正是Bjarne著作的一贯特点,言简意赅而内韵十足。

(本文来源于图老师网站,更多请访问https://www.tulaoshi.com)

下面一步一步地向大家介绍我自己土制佳酿的废料收集系统,可以按照需要自由选用,而不影响其他代码。

2 构造函数和析构函数

C++中提供的构造函数和析构函数很好的解决了自动释放资源的需求。Bjarne有一句名言,“资源需求就是初始化(Resource Inquirment Is Initialization)”。

因此,我们可以将需要分配的资源在构造函数中申请完成,而在析构函数中释放已经分配的资源,只要对象的生存期结束,对象请求分配的资源即被自动释放。

那么就仅剩下一个问题了,如果对象本身是在自由存储区(Free Store,也就是所谓的“堆”)中动态创建的,并由指针管理(相信你已经知道为什么了),则还是必须通过编码显式的调用析构函数,当然是借助指针的delete表达式。

3 智能指针

幸运的是,出于某些原因,C++的标准库中至少引入了一种类型的智能指针,虽然在使用上有局限性,但是它刚好可以解决我们的这个难题,这就是标准库中唯一的一个智能指针::std::auto_ptr<。

它将指针包装成了类,并且重载了反引用(dereference)运算符operator *和成员选择运算符operator -,以模仿指针的行为。关于auto_ptr<的具体细节,参阅《The C++ Standard Library》(中译本:C++标准库)。

例如以下

来源:https://www.tulaoshi.com/n/20160129/1485886.html

延伸阅读
Java跨平台的特性使Java越来越受开发人员的欢迎,但也往往会听到不少的抱怨:用Java开发的图形用户窗口界面每次在启动的时候都会跳出一个控制台窗口,这个控制台窗口让本来非常棒的界面失色不少。怎么能够让通过Java开发的GUI程序不弹出Java的控制台窗口呢?其实现在很多流行的开发环境例如JBuilder、Eclipse都是使用纯Java开发的集成环境...
简介 对于很多初学者来说,往往觉得回调函数很神秘,很想知道回调函数的工作原理。本文将要解释什么是回调函数、它们有什么好处、为什么要使用它们等等问题,在开始之前,假设你已经熟知了函数指针。 什么是回调函数? 简而言之,回调函数就是一个通过函数指针调用的函数。假如你把函数的指针(地址)作为参数传递给另一个...
C#中数组是引用类型,C#定义整型数组方式是:int [] intArray = {1,2,3};或int [] intArray = new int;而C++中定义整型数组的方式是:int intArray[] = {1,2,3};或int * intArray = new int;C#中的数组可以是一维的也可以是多维的,同样也支持矩阵和参差不齐的数组。注意:定义多维数组(矩阵)的方式是[,,]而定义多维“参差矩阵”的方式是[]...
Const 是C++中常用的类型修饰符,常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值是不能被更新的。 1、定义常量 (1)const修饰变量,以下两种定义形式在本质上是一样的。它的含义是:const修饰的类型为TYPE的变量value是不可变的。  TYPE const ValueName = value;      const TYPE ValueName =...
随着计算机信息表示及实现的多媒体化,在许多学习软件、游戏软件,以及多媒体课件制作软件中,经常使用各种图形显示技巧,如图形的推拉、交错、雨滴状、百页窗、积木随机堆叠等显示模式。这样使画面变得更为生动活泼,更能吸引用户,也为更好地发挥软件的功能奠定了基础。本文就Visual C++ 6.0中实现图形的各种显示技巧的原理及具体方法做...

经验教程

228

收藏

64
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部