comp.lang.ada
 help / color / mirror / Atom feed
From: "Nick Roberts" <nick.roberts@acm.org>
Subject: Re: Type conversions on pool-specific access types
Date: Thu, 16 Oct 2003 21:28:07 +0100
Date: 2003-10-16T21:28:07+01:00	[thread overview]
Message-ID: <bmmv0o$olqei$1@ID-25716.news.uni-berlin.de> (raw)
In-Reply-To: g5ksovoq9nkg0tb53rgrn40vjjl7l5cqkb@4ax.com

"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
news:g5ksovoq9nkg0tb53rgrn40vjjl7l5cqkb@4ax.com...

> > ...
> >   declare
> >      Ptr : Base_Ptr := new Derived;
> >   begin
> >      Foo(Ptr);
>
> Yes, in this case. But consider specialized containers of
> Derived descendants:
>
> procedure Derived_Specific (X : Derived);
> type Array_Of_Derived is array (...) of Derived_Ptr;
>
> Now you can call Derived_Specific on any element of
> Array_Of_Derived without an explicit type conversion.
> It is also type safe. If I have only Base_Ptr, I lose that
> advantage and forced to always work in the terms of
> the base type and what is worse, to make casts.

In this situation, I suggest you declare:

   type Derived_Ptr is access Derived'Class;
   type Array_Of_Derived is array (...) of Derived_Ptr;

exactly as you suggest, so you can call:

   Derived_Specific( Array_Of_Derived(...).all );

If you now wish to call Foo for an object designated by a component of the
Array_Of_Derived array, you do indeed need to do a conversion. I think this
can be adequately achieved in Ada 95 by the use of an intermediate general
access type:

   type General_Base_Ptr is access all Base'Class;
   procedure Foo (Object: in General_Base_Ptr);

Now we can call Foo for objects of type Base_Ptr or Derived_Ptr:

   X: Base_Ptr;
   ...
   Foo( General_Base_Ptr(X) );
   Foo( General_Base_Ptr(Array_Of_Derived(...)) );

If you do not need to be able to pass null values, an alternative is to make
the parameter to Foo of an anonymous access type:

   procedure Foo (Object: access Base'Class);

Then the conversions are implicit:

   Foo( X );
   Foo( Array_Of_Derived(...) );

I recognise that this is not the neatest solution imaginable, but I think it
works, and will be reasonably efficient. It has the possible advantage that
you could choose to have Base_Ptr and Derived_Ptr objects stored in
different pools (and the new Foo will still work, since it accepts a general
access type).

> [Finalize should not deallocate Object]
> Theoretically true, but practically, consider a situation
> when objects have to be always allocated in a specific
> pool. For example, on a user-defined stack. Further each
> object has to remove itself from some list. It is made
> upon finalization. The problem is that in this case you
> cannot use the advantages of thin pool-specific pointers.

I repeat that a controlled object should not attempt to deallocate itself
during its own finalisation. In order to cause the deallocation of an
object, an instance of Unchecked_Deallocation should be called at the
appropriate time, which can be expected to: (1) call Finalize for the
object; (2) call Deallocate for the object's pool.

One way to obtain the calling of an instance of Unchecked_Deallocation for
all the objects in a linked list is to declare a controlled type which
contains a pointer to one of the objects in the list, and to implement the
Finalize procedure of this type to chase down the list deallocating objects
as it goes. For example:

   type My_Object;

   type My_Object_Ptr is access My_Object;

   type My_Object is new Ada.Finalization.Controlled with
      record
         Next: My_Object_Ptr;
         ...
      end record;

   type My_Object_List is new Ada.Finalization.Controlled with
      record
         First: My_Object_Ptr;
         ...
      end record;

   procedure Free is new
Ada.Unchecked_Deallocation(My_Object,My_Object_Ptr);

   procedure Finalize (List: in out My_Object_List) is
      Obj, Tmp: My_Object_Ptr;
   begin
      Obj := List.First;
      List.First := null;
      while Obj /= null loop
         Tmp := Obj;
         Obj := Obj.Next;
         Free(Tmp); -- will call member's Finalize and its pool's Deallocate
      end loop;
   end Finalize;

   procedure Do_Something_Using_a_List is
      L: My_Object_List;
   begin
      ... -- add members to the list L
   end; -- L will be finalised here, which will cause the whole list to be
finalised and freed properly

Hope this is helpful!

--
Regards,
Nick Roberts





  reply	other threads:[~2003-10-16 20:28 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2003-10-13 10:34 Type conversions on pool-specific access types Dmitry A. Kazakov
2003-10-16  1:43 ` Nick Roberts
2003-10-16 12:13   ` Dmitry A. Kazakov
2003-10-16 20:28     ` Nick Roberts [this message]
2003-10-17  4:27       ` Nick Roberts
2003-10-18  9:59       ` Dmitry A. Kazakov
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox