Topic: Pointer Comparisons
Author: pabloh@hpwala.wal.hp.com (Pablo Halpern )
Date: Mon, 18 Jan 1993 18:53:39 GMT Raw View
In article <1993Jan2.211538.11320@lpi.liant.com>, pkt@lpi.liant.com (Scott Turner) writes:
|> My perspective, that subobjects are objects, has stood up to 4 years of
|> working with the C++ reference manual and working paper. It fits in better
|> with the common application of the prefix "sub". For example, a subset is
|> so called not because it belongs to a set, but because it _is_ a set
|> subordinate to another set. If a subset were not properly a set, then
|> it never would have been called a subset. Likewise "subobject" would be
|> a poor term if it did not refer to an object.
You cannot arbitrarily make up the english meaning of "sub." Remember,
"subhuman" means "less than human," thus it is very reasonable for a
"subobject" to be "less than an object." In fact, subset is a very poor
example. In math class we were explicitly taught that, "a subset is a
set." This had to be made explicit because it was not *obvious* from the
use of the prefix, "sub." A subset has all of the qualities of a set, but
that does not imply that a subspecies has all of the qualities of a
species, nor that a subobject has all of the qualities of an object.
--
- Pablo
------------------------------------------------------------------------
Pablo Halpern (617) 290-3542
HP Waltham pabloh@hpwarq.wal.hp.com
I am self-employed, so my opinions *do* reflect those of my employer.
However, they may not reflect the opinions of my client.
------------------------------------------------------------------------
Author: jimad@microsoft.com (Jim Adcock)
Date: 24 Dec 92 20:37:26 GMT Raw View
In article <1992Dec23.172735.15352@ucc.su.OZ.AU> maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
|ARM requires non-zero length objects doesnt it?
No, ARM does not make such a requirement. ARM requires sizeof(Ob) to
be greater than zero. And ARM requires new Ob to return a distinct address.
But this is not the same as requiring Ob to have non-zero length.
The basic underlying requirement is that the space that Ob takes as an
element of an array be greater than zero, so that pointers to different
elements in the array have different values. This can be achieved for
zero-length objects by requiring them to have at least one-byte trailing
alignment padding when placed in arrays. When used as a member of a structure,
the object wouldn't necessarily have the same padding and alignment
requirements. For example ARM *explicitly* makes no requirement of
implementations in the following example:
class A {};
class B
{
public:
A a1;
public:
A a2;
};
main()
{
B b;
A* p1 = &(b.a1);
A* p2 = &(b.a2);
if (p1 == p2)
cout << "its undefined according to ARM!\n";
else
cout << "boring case -- but still undefined behavior!\n";
return 0;
}
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Sun, 20 Dec 1992 00:03:41 GMT Raw View
On Pointer Comparisons
----------------------
I propose, not claiming to be the originator of any or all the ideas
here, that the issue of pointer comparisons be resolved as
follows.
1) If two pointers of the same type, (other than void*) compare equal,
then they may be assumed to refer to the same object, subobject,
or component.
Comment.
Allocations by 'new' of empty classes will then require at least one
byte of address space be wasted, otherwise
struct T {};
T* t1=new T;
T* t2=new T;
if(p==q)cout<<"p,q are same object");
gives a false diagnostic.
Inclusion of an empty class in a structure must also have this
property, as must allocations on the stack or in static storage.
The same is true for inheritance:
struct U : public T {};
struct V : public T {}
struct D : public U, public V { ... } d;
T* t1=(U*)&d;
T* t2=(V*)&d;
Alternative.
The alternative rule allows an exception if the classes are empty,
empty meaning either no data members, or better, no data members
and no virtual functions.
This alternative precludes use of empty classes solely to create
unique objects with no operations, but appears to have no other
serious consequences. Since nonempty classes can always be
used to artificially create unique object identities, this
alternative may be viable.
2) Let T be a type. A pointer to T, const T, volatile T, or
const volatile T is called an object pointer. Pointers
to array types are also object pointers.
The address of a function is a function pointer.
A void* is a void pointer.
A pointer obtained by operator new, or taking the address
of a static or auto object, or a pointer explicitly set to 0,
is a domestic pointer (value).
A pointer to a function with external linkage is a domestic
pointer (value).
A domestic pointer is valid if the object from which it was
derived continues to exist, otherwise it is said to dangle,
and is invalid, except that 0 pointers are considered valid.
(If nested functions are introduced, this rule also applied
to them. If dynamic linkage is used, this rule also applies to them)
A function or object pointer obtained by conversion, copying,
or assignment, of a valid domestic pointer is a valid domestic pointer
(except for conversion to void*, which is not a function or object
pointer).
If a (valid) member pointer is bound to a valid non-zero
object pointer, the result is a valid object pointer.
(Appropriate rules for pointers to objects in arrays need
to be included here, allowing for pointer arithmetic).
Two valid domestic pointers of the same type compare equal if they
point to the same object or function.
Two void* compare equal if they were derived from the two
valid domestic pointers that compare equal, and those
pointer values remain valid.
Comment.
These rules explicitly exclude 'foreign' pointers such as those
obtained by operating system calls. In this case the rules
may be obeyed or not, it is implementation defined.
The same applies to invalid pointers, since the memory may be
reclaimed, or the pointers themselves modified by a GC
or compaction algorithm.
3) Combination of (1) and (2) yield an equivalence between
object identity and pointer equality subject to the caveats
mentioned.
Therefore, the inequality operator will be defined by
a!=b <==> !(a==b)
with the same caveats.
Comment
The desired equivalence
a==b <==> a,b refer to the same object
a!=b <==> a,b refer to different objects
is subject to the 3 constraints:
a) nonempty class (if rule 1 alternative is taken)
b) validity (continued existence of the object pointed to)
c) domesticity (exclusion of mangling and foreign suppliers)
4) The operators <,>, <=,>= are implementation defined, unless
the arguments point into the same array or access components
of the same access section in a class, or both, in which
case they reflect the relative positions in the obvious
way (with caveats for empty classes).
(Additional caveats may have to be added here, esp regards
subobject ordering)
If the macro TOTALPTRORDER is defined, the standard pointer
comparisons provide a total order.
5) The standard library function
int ptrorder(void*,void*);
yields a total order as follows:
ptrorder(a,a)==0 (reflexive)
ptrorder(a,b)<0 ==> ptrorder(b,a)>0 (anti-commutative)
ptrorder(a,b)==0 ==> ptrorder(b,a)==0
ptrorder(a,b)<0 && ptrorder(b,c)<0 ==> ptrorder(a,c)<0 (transitive)
If the macro TOTALPTRORDER is defined, ptrorder must
provide the same ordering.
Comment.
ptrorder may return 0 for all arguments. It can be used in algorithms
not requiring any object identity, such as sorts, but not when
equality is required for a uniqeness such as for a b-tree.
6) Ptrorder0
Same as ptrorder, with the additional constraint
ptrorder0(0,a)==0 ==> a==0
Comment.
This function allows 0 to be distinguished. I'm not sure
how useful this is, and whether it should be required or
indicated by a macro variable.
7) ptrcmp
This function returns a total order compatible with ==
ptrcmp(a,b)==0 <==> a==b
It is implementation dependent whether this function is actually
provided or not, if it is, however, it must obey the above
semantics.
To facilitate detection the macro variable PTRCMP is defined
if ptrcmp is available for unrestricted calls, and not otherwise.
If ptrcmp is not available, the user may supply a ptrcmp routine,
which must have the above semantics.
Comment.
ptrcmp is used when object identity is important, for
example an efficient set implementation.
If ptrcmp is not available, it is an indication that in this
environment a client algorithm could not possibly work.
For example in the presence of an incremental compacter that
reordered objects in memory and updated the relevant pointers,
a set implemented by an ordered list could not work,
so the absence of ptrcmp is no loss.
Extension.
The functions
freezeptrcmp()
thawptrcmp()
may also be supplied in systems where pointers may be silently
modified.
The macro FREEZEPTRCMP is defined if these functions are defined.
If the macro PTRCMP is defined, freezing and thawing effects
efficiency only, calls to freezeptrcmp() and thawptrcmp() are optional.
If FREEZEPTRCMP is defined, but PTRCMP is not, then
calling freezeptrcmp() enables ptrcmp to yield a total
order.
After freezptrcmp() is called, the order may be lost.
The freeze function need not stop a compaction routine,
only prevent it destroying a total order.
If PTRCMP is not defined, freezing is mandatory during
sequences of calls to ptrcmp. Inappropriate calls
to ptrcmp may not work if correct freezing and thawing
strategy is not followed.
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: jbn@lulea.trab.se (Johan Bengtsson)
Date: 20 Dec 92 21:03:50 GMT Raw View
John MAX Skaller (maxtal@extro.ucc.su.OZ.AU) wrote:
: On Pointer Comparisons
: ----------------------
: I propose
[...]
: 1) If two pointers of the same type, (other than void*) compare equal,
: then they may be assumed to refer to the same object, subobject,
: or component.
: Comment.
: Allocations by 'new' of empty classes will then require at least one
: byte of address space be wasted, otherwise
[...]
: Inclusion of an empty class in a structure must also have this
: property,[...]
==> Only if adjacent to another member with which it has a common
base class.
: Alternative.
: The alternative rule allows an exception if the classes are empty,
: empty meaning either no data members, or better, no data members
: and no virtual functions.
==> "no virtual functions" is perhaps too restrictive, since that
might unnecessarily preclude implementations that don't use
the "vtbl" scheme, for example by tagging all pointers with
the actual type, or using special hardware (e.g. associative memory).
I think "no data members" must be enough to void all
guarantees on pointer distinctness (in this alternative
to rule (1)).
: This alternative precludes use of empty classes solely to create
: unique objects with no operations, but appears to have no other
: serious consequences. Since nonempty classes can always be
: used to artificially create unique object identities, this
: alternative may be viable.
==> I would agree, but only for "vtbl" like implementations,
since objects under future implementations may very well need
zero storage, even if they have virtual functions. Since we
do not wish to preclude future non-vtbl implementations
(right?), I do _not_ think this alternate rule is a good one.
I think the alternate rule (1) must be
"You can't rely on pointer equivalence for classes that have
no data members"
disqualifying among others many abstract base classes (I know
you John like MI mix-ins, many of those should be affected too).
[...]
[ definition of "domestic" pointers deleted ]
: Two void* compare equal if they were derived from the two
: valid domestic pointers that compare equal, and those
: pointer values remain valid.
==> Two void* should also be allowed to compare equal in
cases where they are not derived from two domestic
pointers that compare equal, i.e.
p1==p2 ==> (void*)p1==(void*)p2,
but not the other way around. The reverse should only hold
if (p1 == p2) is defined, assuming equality comparison
is only defined if p1 and p2 are of the same type, or share
a common base class.
Also note that the common base class of p1 and p2 must not
be an empty class (if the alternative rule (1) is adopted).
: Comment
: The desired equivalence
: a==b <==> a,b refer to the same object
: a!=b <==> a,b refer to different objects
: is subject to the 3 constraints:
: a) nonempty class (if rule 1 alternative is taken)
: b) validity (continued existence of the object pointed to)
: c) domesticity (exclusion of mangling and foreign suppliers)
==> I like the analysis, although I think constraint a) should
be removed, since all classes with no data members must be
considered "empty".
--
--------------------------------------------------------------------------
| Johan Bengtsson, Telia Research AB, Aurorum 6, S-951 75 Lulea, Sweden |
| Johan.Bengtsson@lulea.trab.se; Voice:(+46)92075471; Fax:(+46)92075490 |
--------------------------------------------------------------------------
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Wed, 23 Dec 1992 17:27:35 GMT Raw View
In article <5451@holden.lulea.trab.se> jbn@lulea.trab.se (Johan Bengtsson) writes:
>John MAX Skaller (maxtal@extro.ucc.su.OZ.AU) wrote:
>
>: On Pointer Comparisons
>: ----------------------
[..]
>: Allocations by 'new' of empty classes will then require at least one
>: byte of address space be wasted, otherwise
>[...]
>: Inclusion of an empty class in a structure must also have this
>: property,[...]
>
>==> Only if adjacent to another member with which it has a common
> base class.
Can you have the size different depending ... Yes,
Ok, the size could be zero, and the position of the next object
might be adjusted if required and not otherwise.
>
>: Alternative.
>
>: The alternative rule allows an exception if the classes are empty,
>: empty meaning either no data members, or better, no data members
>: and no virtual functions.
>
>==> "no virtual functions" is perhaps too restrictive, since that
Yes.
> I think "no data members" must be enough to void all
> guarantees on pointer distinctness (in this alternative
> to rule (1)).
> I think the alternate rule (1) must be
>
> "You can't rely on pointer equivalence for classes that have
> no data members"
Fine.
>
> disqualifying among others many abstract base classes (I know
> you John like MI mix-ins, many of those should be affected too).
Well, that just means you want rule(1) and not rule(1A).
There has been disagreement on this so I didnt want to preempt the
outcome here by making a decision. But likely rule 1 will do
because ARM requires non-zero length objects doesnt it?
>
>[ definition of "domestic" pointers deleted ]
I think you mean "definition" of domestic pointers deleted :-)
>
>: Two void* compare equal if they were derived from the two
>: valid domestic pointers that compare equal, and those
>: pointer values remain valid.
>
>==> Two void* should also be allowed to compare equal in
you must mean "required" not "allowed" surely?
> cases where they are not derived from two domestic
> pointers that compare equal, i.e.
>
> p1==p2 ==> (void*)p1==(void*)p2,
Maybe. And maybe this rule is totally wrong!
Consider
class A {} class B : A {}
B* b=new B;
A* a=b;
a==b; // YES after implicit conversion of b to an A
(void*)a == (void*)b; // NO, they point different places
So I think unless I'm wrong here and right before this rule has to
be withdrawn :-(
>
> but not the other way around. The reverse should only hold
> if (p1 == p2) is defined, assuming equality comparison
> is only defined if p1 and p2 are of the same type, or share
> a common base class.
I assume you can only compare pointers of exactly the same
type. All other comparisons must convert one of the pointers first.
>
> Also note that the common base class of p1 and p2 must not
> be an empty class (if the alternative rule (1) is adopted).
>
>: Comment
>
>: The desired equivalence
>
>: a==b <==> a,b refer to the same object
>: a!=b <==> a,b refer to different objects
>
>: is subject to the 3 constraints:
>
>: a) nonempty class (if rule 1 alternative is taken)
>: b) validity (continued existence of the object pointed to)
>: c) domesticity (exclusion of mangling and foreign suppliers)
>
>==> I like the analysis, although I think constraint a) should
> be removed, since all classes with no data members must be
> considered "empty".
If "empty" classes are zero length, you need the caveat, otherwise
you dont.
I really dont know if this sort of thing is viable for the Standard.
The whole of this was to allow certain types of code to be
non-strictly conforming without being non-conforming.
In particular, it might perhaps *allow* vendor supplied
standard routines to muck with pointers without making
programs written using these features non-conforming.
(E.g. Borland and most DOS systems allow construction
and manipulation of pointers with language extensions.).
But I think really all bets might be off. You would
have to replace /pointer/ with /domestic pointer/
throughout most of the standard, eg
x->print(); // x has to be domestic
and what it might ome down to is that all pointers
are assumed domestic in the standard anyhow .. so there
is nothing really to say. Sigh. I'm learning.
Never thought comparing two pointers would be so
hard to understand .. I do it now and then with no great qualms :-)
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------