您的位置:首页 > 其它

ADA程序实例(一个简单的智能指针实现)

2011-11-16 22:28 661 查看
普通的ADA并不含有垃圾收集等托管程序的特性,除非当ADA的目标运行时建立在Java Virtual Machine或.NET系统上。所以从这个对象内存分配角度,ADA和C++基本上是等价的。

ADA提供的语言特性,基本上足以使得ADA能够实现智能指针。当然,是不是有必要在ADA中使用智能指针(考虑ADA常用的思考建模方式),其完善程度(指针的类型,对于OO的支持和对于一般数据的支持)又是另一会儿事。智能指针再智能也不能达到托管程序所能达到内存管理功能(例如简单的引用计数是无法应对孤立环路结构的释放的)。

当然,纯粹展现一下ADA的语言特性,这不失为一个好的例子。

首先是声明(autoptr.ads)。这里显然是一个泛型模块,而其核心类型是指针要处理的对象的类型(private约束是一个很松的约束,尚需查明是不是最松的)。对这个类型可赋予初始化和终止化方法各一。指针实现是指针对象指向一个含引用计数和对象内容的封装对象(Wrapper)。这里比较重要的是封装对象从ada.finalization.controlled继承,这使得能够对其赋值和跨域的状态进行跟踪。其重载函数initialize相当于C++中的无参构造函数,finalize相当于C++中的析构函数,他们分别在对象数据(变量)进域(begin)和出域(end)调用,伴随着变量的诞生和销毁。Adjust比较特殊,也比较关键,它在对象数据被赋值完毕后调用。另外finalize在对象数据被赋值之前也会调用(这个在运行了这个程序才发现)。因为ADA数据赋值永远是针对其直接内容的深拷贝,所以Adjust可用于对收入数据的处理,基本上起到了拷贝构造函数或赋值重载的作用。

spec中提供了一些主要的功能,如所指对象的获取,指针相等的判断的等号重载(根据指针所指对象的一致性而非指针对象本身相同性),以及一个新建空对象的操作。

with Ada.Finalization;

generic
-- type of the target the pointer is dealing with
type target_t is private;

-- handlers invoked on initialization and finalization respectivelys
target_initialize : access procedure(target : in out target_t) := null;
target_finalize : access procedure(target : in out target_t) := null;

package autoptr is

type Pointer is new Ada.Finalization.Controlled with private;

-- returns the targeted object pointer 'p' points to
function target(p : Pointer) return target_t;

-- override of equal sign that returns if two pointers are considered equal
-- in which case they are pointing to the same wrapper/target
function "="(left, right : Pointer) return boolean;

-- creates an new instance of target and returns a pointer that points to it
function create return Pointer;

-- returns the number of pointers referencing the target pointer p points to
function numrefs(p : Pointer) return integer;

private

-- wrapper that wraps around an instance of target
type wrapper_t is tagged
record
target : target_t;
reference_counter : integer;
end record;

-- type of access to wrapper for pointer to point to wrapper
type wrapper_access is access all wrapper_t;

-- data definition of pointer type
type Pointer is new Ada.Finalization.Controlled with
record
wrapper : wrapper_access;
end record;

-- initializer
overriding procedure Initialize(p : in out Pointer);

-- adjuster that is called after assignment of 'p'
overriding procedure Adjust(p : in out Pointer);

-- finalizer (destructor) of the pointer type for dealing with referencing
overriding procedure Finalize(p : in out Pointer);

end autoptr;


知道spec的这些要点,就能完成实现(autoptr.adb),这其中在关键步骤上进行了打印。注意Finalize函数中一开始的指针判断,这从Finalize的特点看是必须的(这反映在执行结果中)。

with Ada.Unchecked_Deallocation;
with ada.text_io; use Ada.text_io;

package body autoptr is

-- instantiate a wrapper deallocation procedure
procedure free_wrapper is new Ada.Unchecked_Deallocation
(Object=> wrapper_t, Name => wrapper_access);

-- returns the targeted object poiner 'p' points to
function target(p : Pointer) return target_t is
begin
-- wrapper is guaranteed to be available
-- if not an exception should be thrown by the system for now
return p.wrapper.target;
end target;

-- creates an new instance of target and returns a pointer that points to it
function create return Pointer is
p : Pointer;
begin
put_line("creating");

p.wrapper := new wrapper_t;
put_line(" step 1");

if target_initialize /= null then
target_initialize(p.wrapper.target);
end if;
put_line(" step 2");

p.wrapper.reference_counter := 1;
put_line(" step 3");

put_line("'create' returning");
return p;
end create;

-- override of equal sign that returns if two pointers are considered equal
-- in which case they are pointing to the same wrapper/target
function "="(left, right : Pointer) return boolean is
begin
return left.wrapper = right.wrapper;
end "=";

-- returns the number of pointers referencing the target pointer p points tos
function numrefs(p : Pointer) return integer is
begin
if p.wrapper = null then
return 0;
end if;

return p.wrapper.reference_counter;
end numrefs;

-- private methods

-- finalizes the target and release the allocation
procedure finalize_wrapper(p : in out wrapper_access) is
begin
if target_finalize /= null then
target_finalize(p.target);
end if;

free_wrapper(p);
end finalize_wrapper;

-- initializer
overriding procedure Initialize(p : in out Pointer) is
begin
put_line("initializing");
null;  -- do nothing; what could be done is instantiate a wrapper
put_line("initialized");
end Initialize;

-- adjuster that is called after assignment of 'p'
overriding procedure Adjust(p : in out Pointer) is
begin
put_line("adjusting");
p.wrapper.reference_counter := p.wrapper.reference_counter + 1;
put_line("adjusted");
end Adjust;

overriding procedure Finalize(p : in out Pointer) is
begin
put_line("finalizing");
if p.wrapper = null then
put_line(" wrapper is null");
return;
end if;

p.wrapper.reference_counter := p.wrapper.reference_counter - 1;
put(" refcount = "); put_line(integer'Image(p.wrapper.reference_counter));
-- allowing 'less than' is purely for tolerating erroneous condition
if p.wrapper.reference_counter <= 0 then
finalize_wrapper(p.wrapper);
end if;
put_line("finalized");
end Finalize;

begin
null;
end autoptr;


最后是一个演示程序(autoptr_demo.adb),只覆盖了一个简单的创建和赋值,未充分测试。

with Ada.Strings; use Ada.Strings;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;
with autoptr;

procedure autoptr_demo is
type myrec_t is tagged record
id    : integer;
name  : string(1..10);
end record;

id : integer := 1;

procedure myrecinit(myrec : in out myrec_t) is
begin
myrec.id := id;
id := id + 1;
myrec.name := 10 * ' ';
myrec.name := overwrite(myrec.name, 1, "rec");
myrec.name := overwrite(myrec.name, 4, trim(integer'Image(id), Both));
put("record{");
put(integer'Image(myrec.id)); put("; '"); put(myrec.name);
put_line("'} created");
end myrecinit;

package myptr is new autoptr(target_t => myrec_t,
target_initialize => myrecinit'Access);

p1, p2 : myptr.Pointer;

begin
p1 := myptr.create;
put("reference count of p1 is "); put_line(integer'Image(p1.numrefs));

p2 := p1;
put("reference count of p2 is "); put_line(integer'Image(p2.numrefs));

put("p2.name = '"); put(p2.target.name); put_line("'");

end;


运行结果(其中wrapper is null说明在赋值前的Finalize调用作用在了未赋值指针上了):

initializing

initialized

initializing

initialized

initializing

initialized

creating

step 1

record{ 1; 'rec2 '} created

step 2

step 3

'create' returning

adjusting

adjusted

finalizing

refcount = 1

finalized

finalizing

wrapper is null

adjusting

adjusted

finalizing

refcount = 1

finalized

reference count of p1 is 1

finalizing

wrapper is null

adjusting

adjusted

reference count of p2 is 2

p2.name = 'rec2 '

finalizing

refcount = 1

finalized

finalizing

refcount = 0

finalized
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: