From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,2866100c9a2b8ce7 X-Google-Attributes: gid103376,public From: bobduff@world.std.com (Robert A Duff) Subject: Re: Free'ing extended types Date: 1996/04/29 Message-ID: #1/1 X-Deja-AN: 152028824 references: <3183AC75.335C@ehs.ericsson.se> <3184803D.1208@ehs.ericsson.se> organization: The World Public Access UNIX, Brookline, MA newsgroups: comp.lang.ada Date: 1996-04-29T00:00:00+00:00 List-Id: In article <3184803D.1208@ehs.ericsson.se>, Jonas Nygren wrote: >Robert Dewar wrote: >> You seem to have the wrong idea of what erroneous is about. An erroneous >> execution is one whose semantics is not specified by the reference >> manual. You seem to think this means that it wlil blow up or do >> something wrong. Not at all! It *may* blow up but it does not have to! Robert is correct in general about erroneousness, but in *this* case, the RM actually says that it's erroneous on some implementations, and not others. >Murphy's law: If it can blow up - it will blow up. In a way, you're lucky if it *does* blow up. Sometimes, it works fine. Until some customer gets ahold of the code, or until somebody tries to port the code, or you get an updated compiler or something (and the original programmer has moved to Mars). >I personally take a very simplistic approach to never use a construct >that I know can blow up. Not even by accident? ;-) >I repeat my original question here: OK, I'll try to answer. Each access type has a storage pool. Pools can be shared among many access types. However, a *single* access type has exactly one pool. There is only one access type in your example, so, clearly everything is allocated in the same pool. So your example is *not* erroneous. The fact that this pool contains A's and B's is irrelevant -- what matters is the access type. >with Ada.Unchecked_Deallocation; >procedure St is > type a is tagged record X : Integer; end record; > type ap is access all a'class; > procedure free is new Ada.unchecked_deallocation(A'class, ap); > type b is new a with record > Y : Integer; end record; -- a is extended > > p : ap := new b; >begin > free(p); -- erroneous ?? >end St; > >Could the call on free result in erroneous execution (in any conceivable >law abiding implementation of Ada). No. However, consider: with Ada.Unchecked_Deallocation; procedure St is type a is tagged record X : Integer; end record; type ap is access all a'class; procedure free is new Ada.unchecked_deallocation(A'class, ap); type b is new a with record Y : Integer; end record; -- a is extended type BP is access all B'Class; -- ADDED THIS p : BP := new b; -- CHANGED THIS q: AP := AP(p); -- ADDED THIS begin free(Q); -- erroneous ?? -- CHANGED THIS end St; Now, Q is being freed from a different access type than the one for which it was allocated. It is implementation-defined whether or not this is erroneous! (Which is subtly different from just being plain old erroneous.) This is because it is implementation defined whether AP and BP share the same pool. In retrospect, I believe this is a language design flaw, for obvious reasons. However, there is probably a de-facto standard. I would be very surprised if AP and BP did *not* share the same pool in any implementation. (Any implementers care to comment?) To be safe: Given a hierarchy of tagged types, allocate them all using the *same* access type. Then, if necessary, convert this to whatever other access types you like. When deallocating, convert things back to the original access type. And put all the allocation and deallocation in a single package, so you easily manage these conventions, and you won't screw up by mistake. (That's a good idea anyway -- e.g. you might want to instrument allocations someday, so you can tell how much memory you're allocating, or track down storage leaks, or whatever.) Alternatively, you can say things like "for BP'Storage_Pool use AP'Storage_Pool;". Or, you could say "for BP'Storage_Size use 0;", which will prevent people from accidentally allocating using type BP, assuming your convention is to always use type AP. To be safer: Buy a compiler with garbage collection. ;-) - Bob