comp.lang.ada
 help / color / mirror / Atom feed
* Re: Deallocating an object referenced via a classwide access type.
  2000-01-11  0:00 Deallocating an object referenced via a classwide access type Aidan Skinner
@ 2000-01-10  0:00 ` Matthew Heaney
  2000-01-11  0:00   ` Matthew Heaney
  2000-01-11  0:00 ` Laurent Guerby
  2000-01-11  0:00 ` Tucker Taft
  2 siblings, 1 reply; 5+ messages in thread
From: Matthew Heaney @ 2000-01-10  0:00 UTC (permalink / raw)


In article <slrn87l2rt.15e.aidan@skinner.demon.co.uk> , 
aidan@skinner.demon.co.uk (Aidan Skinner) wrote:

> with Ada.Finalization;
> package Foo_Package is
>
>   type Foo is new Ada.Finalization.Controlled with private;
>
>   type Foo_Access is access all Foo'Class;
>
>   type New_Foo is new Foo with private;
>
> private
>
>   type Foo is new Ada.Finalization.Controlled with record
>      My_Thing : Foo_Access := null;
>   end Foo;
>
>   type New_Foo is new Foo with null record;
>
>   procedure Deallocate (Object : in out Foo);
>
> end Foo_Package;
>
> How do I deallocate My_Thing?
>
> I can't use Ada.Unchecked_Deallocation, since My_Thing might be a Foo
> or it might be a New_Foo.
>
> A quick search through the RM and various text books has proven
> fruitless. :((

I show how to do this in the design patterns archive.  Do a search for
"free" and see what drops out.

<http://www.acm.org/archives/patterns.html>

Method #1

Yes, you can deallocate an object, designated by an access-to-classwide
access object, by using an instantiation of Unchecked_Deallocation.
(Note carefully that in the declaration of UC, formal type Object is
indefinite, which means a class-wide type is acceptable.)


  type T is abstract tagged null record;

  type TA is access all T;

  procedure Free is
    Unchecked_Deallocation (T, TA);

  O : TA := <some object in T'Class>;
declare
  Free (O);  -- yes, this is perfectly legal


Method #2

However, realize that the RTS is going to have to carry around a lot of
baggage whenever you declare an access type that designated a class-wide
type.  It may be better to simply assume this responsibility yourself,
by using a template method.

The basic idea is to declare a private operation (similar to what you
have in your example) that does the actual deallocation of the specific
type, and to call this operation by dispatching on the tag of the object
whose type is class-wide.  Like this:

package P is

  type T (<>) is abstract tagged limited null record;  --0

  type TA is access all T'Class;
  for TA'Storage_Size use 0;  -- avoid RTS baggage

  <primitive ops for types in T'Class>

  procedure Free (O : in out TA);     --1

private

  procedure Do_Free (O : access T);  --2, 3

end P;


Points about above spec:

0) Declare the type (class) as limited and indefinite.  This prevents
clients from declaring their own instances, and forces them to create
instances by using a constructor provided by each specific type in the
class.


1) Free is a "template method," otherwise known as a "class-wide
operation."  It takes an access object, which designates a class-wide
type, and deallocates the object (by calling Do_Free -- see body below).


2) Do_Free is a "hook method."  It is overridden by each specific type
in the class, and deallocates the object according to the storage
management policy specific to that type.

3) No, this can't be declared as abstract, because it's private.  So we
declare it as non-abstract, and give it a null body.


package body P is

  procedure Do_Free (O : access T) is
  begin
    null;
  end;

  procedure Free (O : in out TA) is
  begin
    if O /= null then
      Do_Free (O);      -- dispatch according to O's tag
      O := null;
    end if;
  end;

end P;


package P.C is

  type NT is new T with private;

  <override primitive ops>

  function New_NT return TA;     --1

private

  type NT is new T with record ...;

  procedure Do_Free (O : access NT);  --2

end P.C;


Comments about above spec:

1) Function New_NT is the constructor for specific type NT.  A client
*must* call this function in order to create a new instance.  The
abstraction (here, P.C.NT) is free to create and delete instances using
whatever storage management policy is appropriate for the type.


2) Do_Free is the hook method.  It can be implemented as an
instantiation of UC, or whatever.


package body P.C is

  type NTA is access all NT;  -- pointer to specific type

  procedure Deallocate is
    new Unchecked_Deallocation (NT, NTA);

  procedure Do_Free (O : access NT) is

    OA : NTA := NTA (O);
  begin
    Deallocate (OA);
  end;

  function New_NT return TA is

    O : constant NTA := NTA'(new NT);
  begin
    <init O>
    return TA (O);   -- or O.all'Access?
  end;

end P.C;



One more point: you seem to be trying to implement a smart pointer in
your example.  If you are, then you can read the Smart Pointers post in
the design patterns archive.  Search for "smart pointer" in the title.

<http://www.acm.org/archives/patterns.html>

Basically, instead of constructors returning an access object directly,
they return a "handle", which is a private type, implemented as a
private derivation of Controlled, and which contains an access object.
Clients don't actually manipulate access objects directly, only handles.

Send me some email if any of this is unclear.

Matt
<mailto:matthew_heaney@acm.org>




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Deallocating an object referenced via a classwide access type.
  2000-01-10  0:00 ` Matthew Heaney
@ 2000-01-11  0:00   ` Matthew Heaney
  0 siblings, 0 replies; 5+ messages in thread
From: Matthew Heaney @ 2000-01-11  0:00 UTC (permalink / raw)


In article <387aa062_4@news1.prserv.net> , "Matthew Heaney" 
<matthew_heaney@acm.org> wrote:

> The basic idea is to declare a private operation (similar to what you
> have in your example) that does the actual deallocation of the specific
> type, and to call this operation by dispatching on the tag of the object
> whose type is class-wide.  Like this:
>
> package P is
>
>   type T (<>) is abstract tagged limited null record;  --0
>
>   type TA is access all T'Class;
>   for TA'Storage_Size use 0;  -- avoid RTS baggage
>
>   <primitive ops for types in T'Class>

Oops!  I forgot to mention that primitive ops for T take access
parameters.  Like this:

  procedure Op (O : access T);

This is so, in order to avoid having to explicitly dereference the
access object returned by constructors.


--
Get the FAQs about evolution and creationism.

<http://www.talkorigins.org/origins/faqs.html>




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Deallocating an object referenced via a classwide access type.
  2000-01-11  0:00 Deallocating an object referenced via a classwide access type Aidan Skinner
  2000-01-10  0:00 ` Matthew Heaney
  2000-01-11  0:00 ` Laurent Guerby
@ 2000-01-11  0:00 ` Tucker Taft
  2 siblings, 0 replies; 5+ messages in thread
From: Tucker Taft @ 2000-01-11  0:00 UTC (permalink / raw)


Aidan Skinner wrote:
> 
> Mkay.
> 
> I have the following package:
> 
> with Ada.Finalization;
> package Foo_Package is
> 
>   type Foo is new Ada.Finalization.Controlled with private;
> 
>   type Foo_Access is access all Foo'Class;
> 
>   type New_Foo is new Foo with private;
> 
> private
> 
>   type Foo is new Ada.Finalization.Controlled with record
>      My_Thing : Foo_Access := null;
>   end Foo;
> 
>   type New_Foo is new Foo with null record;
> 
>   procedure Deallocate (Object : in out Foo);
> 
> end Foo_Package;
> 
> How do I deallocate My_Thing?
> 
> I can't use Ada.Unchecked_Deallocation, since My_Thing might be a Foo
> or it might be a New_Foo.

That is not your concern.  The run-time system knows which is
which, because of the presence of the run-time tag.  What matters is
which access type you use when instantiating Unchecked_Deallocation --
so long as you instantiate using Foo_Access/Foo'Class as the
actual parameters, it should work fine.

The only problem in this general vicinity is that if you allocate
using one access type, you must deallocate using an access type
that uses the same storage pool (RM95 13.11.2(16)).  
The safest thing is to allocate and deallocate using 
the same access type, but you can also specify all of your 
access types to use the same storage pool by adding something like:
   for Fum_Access'Storage_Pool use Foo_Access'Storage_Pool;
to all other access types to which you might convert a value of
type Foo_Access.
> 
> A quick search through the RM and various text books has proven
> fruitless. :((
> 
> - Aidan

-- 
-Tucker Taft   stt@averstar.com   http://www.averstar.com/~stt/
Technical Director, Distributed IT Solutions  (www.averstar.com/tools)
AverStar (formerly Intermetrics, Inc.)   Burlington, MA  USA




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Deallocating an object referenced via a classwide access type.
@ 2000-01-11  0:00 Aidan Skinner
  2000-01-10  0:00 ` Matthew Heaney
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Aidan Skinner @ 2000-01-11  0:00 UTC (permalink / raw)


Mkay.

I have the following package:

with Ada.Finalization;
package Foo_Package is 

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

  type Foo_Access is access all Foo'Class;

  type New_Foo is new Foo with private;

private

  type Foo is new Ada.Finalization.Controlled with record
     My_Thing : Foo_Access := null;
  end Foo;

  type New_Foo is new Foo with null record;

  procedure Deallocate (Object : in out Foo);

end Foo_Package;

How do I deallocate My_Thing?

I can't use Ada.Unchecked_Deallocation, since My_Thing might be a Foo
or it might be a New_Foo.

A quick search through the RM and various text books has proven
fruitless. :((

- Aidan

-- 
"I consider your own preference for not breeding to be a service
to usenet."
http://www.skinner.demon.co.uk/aidan/




^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Deallocating an object referenced via a classwide access type.
  2000-01-11  0:00 Deallocating an object referenced via a classwide access type Aidan Skinner
  2000-01-10  0:00 ` Matthew Heaney
@ 2000-01-11  0:00 ` Laurent Guerby
  2000-01-11  0:00 ` Tucker Taft
  2 siblings, 0 replies; 5+ messages in thread
From: Laurent Guerby @ 2000-01-11  0:00 UTC (permalink / raw)


Aidan wrote:
> I can't use Ada.Unchecked_Deallocation, since My_Thing might be a Foo
> or it might be a New_Foo.

May be I'm missing something obvious about your question and/or the
Ada RM but the code attached at the end of this message works for
AFAIK (I edited your spec so that it compiles ;-). The only thing
special (due to the class wide nature of the Object formal) is that
the Finalize call made as part of the Free call before returning the
memory to the system will be dispatching (you didn't provide Finalize
on Foo but I guess you have one ;-).

--LG

with Ada.Unchecked_Deallocation;
package body Foo_Package is

   procedure Deallocate (Object : in out Foo) is
      procedure Free is new Ada.Unchecked_Deallocation (Foo'Class, Foo_Access);
   begin
      Free (Object.My_Thing);
   end Deallocate;

end Foo_Package;

with Ada.Finalization;
package Foo_Package is

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

  type Foo_Access is access all Foo'Class;

  type New_Foo is new Foo with private;

private

  type Foo is new Ada.Finalization.Controlled with record
     My_Thing : Foo_Access := null;
  end record;

  procedure Deallocate (Object : in out Foo);

  type New_Foo is new Foo with null record;

end Foo_Package;






^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2000-01-11  0:00 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2000-01-11  0:00 Deallocating an object referenced via a classwide access type Aidan Skinner
2000-01-10  0:00 ` Matthew Heaney
2000-01-11  0:00   ` Matthew Heaney
2000-01-11  0:00 ` Laurent Guerby
2000-01-11  0:00 ` Tucker Taft

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