Thread View: comp.std.c++
10 messages
10 total messages
Started by Paul Lucas
Tue, 18 Aug 1992 04:56
this == 0 for nonvirtual functions
Author: Paul Lucas
Date: Tue, 18 Aug 1992 04:56
Date: Tue, 18 Aug 1992 04:56
63 lines
2756 bytes
2756 bytes
The ARM, p. 176 says:
The effect of calling nonstatic member function of a
class C for something that is not an object of class C
is undefined.
For example,
((X*)0)->f();
is not guaratneed to work. ... Even for non-virtual
functions, one should expect this trick to fail
eventually because specialized C++ implementations might
assume something about the contents of objects even when
calling nonvirtual functions. In particular, on might
expect implementaions instrumented for debugging,
interpretersm and implementations supporting dynamic
loading to be sensitive to "housekeeping" information
placed in the objects by the compiler.
Natually, this trick would work only f() either checks
its 'this' pointer before accessing any members or...
IMHO, the ability to *depend upon* the (desired) fact that
*calling* a non-virtual member-function with a nil pointer is
*guaranteed* to be harmless seems worthwhile (and its addition
to the language wouldn't break anything as far as I can tell).
The alleged existence of "specialized C++ implementations" seems
rather a "fringe" reason for saying that it's undefined; the
standard could *make* it defined.
The last paragraph is also vague; does it really mean "...this
trick is *guaranteed* to work only if f() either checks its
'this' pointer before accessing any members...?"
The simple example where this is handly is a linked-list class
where the objects are always dealt with via pointer. The class,
in its quest for robustness, could easily check its 'this'
pointer before doing anything; consider also:
void Link::DeleteAll() {
for ( Link *p = this, *q; p; p = q ) {
q = p->next;
delete p;
}
}
There's an initial test on 'this' so if I call DeleteAll() with
a nil pointer, it should do nothing. It would be nice to not
have to check for nil in such cases; requiring it is prone to
user error.
To reiterate, all I would like is to guarantee that the *call*
to a non-virtual member-function will succeed and that it's my
responsibility to check for a non-nil 'this'.
Comments?
--
- Paul J. Lucas University of Illinois
AT&T Bell Laboratories at Urbana-Champaign
Naperville, IL pjl@cs.uiuc.edu
Re: this == 0 for nonvirtual functions
Author: Patrick Smith
Date: Wed, 19 Aug 1992 04:22
Date: Wed, 19 Aug 1992 04:22
31 lines
1545 bytes
1545 bytes
pjl@sparc10.cs.uiuc.edu (Paul Lucas) writes:
| IMHO, the ability to *depend upon* the (desired) fact that
| *calling* a non-virtual member-function with a nil pointer is
| *guaranteed* to be harmless seems worthwhile (and its addition
| to the language wouldn't break anything as far as I can tell).
If this change to the language were made, it might be appropriate
not to include the case of calling a member function with a nil
pointer to a class virtually derived from the class where the
function is defined:
class Base { void f(); };
class Derived : public virtual Base {};
...
Derived* p;
p->f();
If I understand correctly, in most implementations the conversion
of p to a Base* will require examining the contents of *p.
If p may be 0, then the compiler must insert extra code to
treat this case correctly.
Of course, this extra code is currently necessary for all conversions
of a Derived* to a Base* where the compiler can't be sure that
the pointer is non-nil. So perhaps the extra overhead for the
function calls wouldn't be seen as significant.
--
Patrick Smith
uunet.ca!frumious!pat
pat%frumious.uucp@uunet.ca
Re: this == 0 for nonvirtual functions
Author: Jim Adcock
Date: Thu, 20 Aug 1992 21:54
Date: Thu, 20 Aug 1992 21:54
27 lines
2096 bytes
2096 bytes
In article <1992Aug18.045605.14220@sunb10.cs.uiuc.edu> pjl@sparc10.cs.uiuc.edu (Paul Lucas) writes: | To reiterate, all I would like is to guarantee that the *call* | to a non-virtual member-function will succeed and that it's my | responsibility to check for a non-nil 'this'. First, note that this would not come at "zero" cost. As in the case of assigning to a reference, requiring "this" to be non-null allows compilers to avoid generating code to preserve nullness when adjusting pointers in the case of MI. In the case of references, this issue has already been reviewed and decided upon: one is not allowed to have null references. Further, note that member functions can be called either on a pointer or on a reference. If the language were to PERMIT calling member functions on a null pointer, such would not ALLOW *you* to test for null "this" inside you member functions, but rather would REQUIRE all of *us* to test for null "this" inside ALL *our* non-virtual member functions -- because a user of our class such as yourself could then legally call *our* member functions via a null pointer. If such were the case then, the only sane remedy C++ programmers would have would be to declare all their member functions virtual. Then *you* *still* could not legally call these members on a null pointer -- but many member functions would now be needlessly slow and generate needlessly large code. I suggess instead that you use friend functions or static member functions where you feel you must address null pointers implicitly. Alternately, note that the users of your class may be the ones in the best position to perform the null pointer tests [explicitly].
Re: this == 0 for nonvirtual functions
Author: Paul Lucas
Date: Fri, 21 Aug 1992 04:44
Date: Fri, 21 Aug 1992 04:44
78 lines
4571 bytes
4571 bytes
In <1992Aug20.215455.17279@microsoft.com> jimad@microsoft.com (Jim Adcock) writes: >In article <1992Aug18.045605.14220@sunb10.cs.uiuc.edu> pjl@sparc10.cs.uiuc.edu (Paul Lucas) writes: >| To reiterate, all I would like is to guarantee that the *call* >| to a non-virtual member-function will succeed and that it's my >| responsibility to check for a non-nil 'this'. >First, note that this would not come at "zero" cost. As in the case of >assigning to a reference, requiring "this" to be non-null allows compilers >to avoid generating code to preserve nullness when adjusting pointers >in the case of MI. In the case of references, this issue has already >been reviewed and decided upon: one is not allowed to have null references. I was under the impression that for MI, once a this pointer became zero it has to stay zero, so it constitutes a special-case now. Hence, why wouldn't be a zero-cost feature? >Further, note that member functions can be called either on a pointer or >on a reference. If the language were to PERMIT calling member functions >on a null pointer, such would not ALLOW *you* to test for null "this" inside >you member functions, but rather would REQUIRE all of *us* to test for >null "this" inside ALL *our* non-virtual member functions -- because a user >of our class such as yourself could then legally call *our* member functions via >a null pointer. If such were the case then, the only sane remedy C++ >programmers would have would be to declare all their member functions virtual. >Then *you* *still* could not legally call these members on a null pointer -- >but many member functions would now be needlessly slow and generate needlessly >large code. I don't think that it would require everyone to test this for zero. I had said that this would be usedful only if a majority of member-function calls were made via a pointer, i.e., linked-list and perhaps other container classes that use linked lists for their implementation. Such a class would have as part of it's documentation: "This class is null-this safe" meaning it would do something sensible, or more likely nothing at all, for a null this pointer. Other "concrete object" type classes, i.e., complex numbers, would have no need of being "null-this safe." It wasn't my intent to introduce the feature just so all programmers could forbid it by making everything virtual. If programmers elected not to check the this pointer, then the program, if a member is accessed via a null-this, would most likely crash or at least be undefined; this is _exactly_ the way language is defined now; hence, for programmers who ignore it, the (errant) behavior of their programs is unchanged. ***************************************************************** Hence, adding my proposal changes nothing for those who ignore it. ***************************************************************** Again, all I want is the *call* to succeed; after that, I'm on my own. >I suggess instead that you use friend functions or static member functions >where you feel you must address null pointers implicitly. Alternately, note >that the users of your class may be the ones in the best position to perform >the null pointer tests [explicitly]. Perhaps [with regard to users checking null tests]; but I think that one of the _themes_ of programming in C++ is to eliminate tedium and errors introduced thereby: virtual functions eliminate switch statements missing a case; exception-handling will eliminate having to check the return value from new to see if it failed, etc. I see my (modest) proposal in the same light. Further comments? -- - Paul J. Lucas University of Illinois AT&T Bell Laboratories at Urbana-Champaign Naperville, IL pjl@cs.uiuc.edu
Re: this == 0 for nonvirtual functions
Author: Andrew Koenig
Date: Fri, 21 Aug 1992 14:30
Date: Fri, 21 Aug 1992 14:30
24 lines
1602 bytes
1602 bytes
Perhaps someone might like to try to construct an example of why it might actually be useful to allow this==0 in a member function. I've been away, so I've missed some messages, but so far the only justification I've seen is statement like `it seems like a good idea.' I find it hard to imagine why it would be useful. A member function that never looks at `this' could just as well be made static; one that actually uses `this' had better not be called with this==0. Thus it appears that the only useful cases are: 1. a function that actually checks if this==0 and does different things depending on the result, or 2. a function that looks at this only if one of its arguments has a particular value. Both of these cases seem contrived to me, to the extent that I would expect to be able to accomplish an equivalent thing more elegantly by other means. Can someone actually come with a useful example? -- --Andrew Koenig ark@europa.att.com
Re: this == 0 for nonvirtual functions
Author: Paul Lucas
Date: Sat, 22 Aug 1992 01:14
Date: Sat, 22 Aug 1992 01:14
101 lines
4339 bytes
4339 bytes
In <23512@alice.att.com> ark@alice.att.com (Andrew Koenig) writes:
>Perhaps someone might like to try to construct an example of why
>it might actually be useful to allow this==0 in a member function.
>I've been away, so I've missed some messages, but so far the only
>justification I've seen is statement like `it seems like a good idea.'
>I find it hard to imagine why it would be useful. A member function
>that never looks at `this' could just as well be made static;
>one that actually uses `this' had better not be called with this==0.
>Thus it appears that the only useful cases are:
> 1. a function that actually checks if this==0 and does different
> things depending on the result, or
> 2. a function that looks at this only if one of its arguments has
> a particular value.
>Both of these cases seem contrived to me, to the extent that I would
>expect to be able to accomplish an equivalent thing more elegantly by
>other means.
>Can someone actually come with a useful example?
My original example is for classes whose objects are dealt with
almost exclusively via pointer, e.g., canonical linked-list
classes or other container classes that use linked-lists for
their implementation.
The example I gave was the member-function:
void Link::DeleteAll() {
for ( Link *p = this, *q; p; p = q ) {
q = p->next;
delete p;
}
}
where the Link class is what you'd expect, i.e.:
class Link {
Link *prev, *next;
// ...
};
The DeleteAll() member, if pass a nil pointer, would (should) do
nothing because its this == 0 to start out.
Also consider:
Link* Link::Cut( int how_many = 1 ) {
// "cut out" how_many links starting at this
// and return a pointer to the new sub-list.
// If how_many == 0, return 0
}
void Link::Delete( int how_many = 1 ) {
Cut( how_many )->DeleteAll();
// Note that if Cut() returns nil, it would be
// if calls where this == 0 were guaranteed to
// work.
}
There are also many other examples along similar lines where not
having to check for this == 0 would be nice. Clearly, these
members can not be static.
To reiterate (for Andrew's sake), I also think that one of the
_themes_ in C++ is to lessen or eliminate tedium and errors
introduced thereby, e.g., virtual functions eliminate missing
cases in swith statements, exception-handling (when it gets
here) to eliminate explicit checks for nil pointers returned by
new() (among other things), etc. I seem my (modest) proposal in
the same light.
Again, to reiterate (for Andrew's sake), I think it's a
zero-cost feature; code that works now will continue to work,
and programmers who ignore it will be unaffected, i.e., if they
don't check 'this' their programs will exhibit undefined
behavior (by trying to access members) and "undefined behavior"
is what happens now anyway.
If nothing else, I would at _least_ like those two seemingly
contradictory paragraphs in the ARM explained, i.e., the ones
that say:
...calling a non-virtual member-function for something
that is not an object should be expected to fail
eventually... (or something along those lines)
and:
Naturally, this trick would work if the member were to
check its this pointer before accessing any members...
Does the latter sentence mean that it really _is_ ok to make the
_call_ with a this == 0, i.e., do I already have what I want?
Thanks in advance.
--
- Paul J. Lucas University of Illinois
AT&T Bell Laboratories at Urbana-Champaign
Naperville, IL pjl@cs.uiuc.edu
Re: this == 0 for nonvirtual functions
Author: Patrick Smith
Date: Sat, 22 Aug 1992 03:17
Date: Sat, 22 Aug 1992 03:17
34 lines
1884 bytes
1884 bytes
pjl@sparc10.cs.uiuc.edu (Paul Lucas) writes:
|In <1992Aug20.215455.17279@microsoft.com> jimad@microsoft.com (Jim Adcock) writes:
|
|>In article <1992Aug18.045605.14220@sunb10.cs.uiuc.edu> pjl@sparc10.cs.uiuc.edu (Paul Lucas) writes:
|>| To reiterate, all I would like is to guarantee that the *call*
|>| to a non-virtual member-function will succeed and that it's my
|>| responsibility to check for a non-nil 'this'.
|
|>First, note that this would not come at "zero" cost. As in the case of
|>assigning to a reference, requiring "this" to be non-null allows compilers
|>to avoid generating code to preserve nullness when adjusting pointers
|>in the case of MI. In the case of references, this issue has already
|>been reviewed and decided upon: one is not allowed to have null references.
|
| I was under the impression that for MI, once a this pointer became
| zero it has to stay zero, so it constitutes a special-case now.
| Hence, why wouldn't be a zero-cost feature?
class Derived : public Base1, public Base2 {};
Derived* p;
Base2* q = p;
// Here the compiler must guarantee that if p was 0,
// then q will be 0. This might require extra code
// to be generated and executed.
p->Base2::f();
// Here the compiler is allowed to _assume_ that p is not 0,
// so the extra code to handle the case p == 0 is not needed.
--
Patrick Smith
uunet.ca!frumious!pat
pat%frumious.uucp@uunet.ca
Re: this == 0 for nonvirtual functions
Author: Andrew Koenig
Date: Sat, 22 Aug 1992 15:52
Date: Sat, 22 Aug 1992 15:52
58 lines
2538 bytes
2538 bytes
In article <1992Aug22.011400.14896@sunb10.cs.uiuc.edu> pjl@sparc6.cs.uiuc.edu (Paul Lucas) writes:
> The example I gave was the member-function:
> void Link::DeleteAll() {
> for ( Link *p = this, *q; p; p = q ) {
> q = p->next;
> delete p;
> }
> }
Because this example ultimately says `delete this' (because p == this
and it says `delete p'), I am already tempted to dismiss it out of hand.
I think it's a Bad Idea to write member functions that invalidate their
object, because it is so far away from what lots of people will expect.
Putting that aside, though, I don't see why it's any harder to make DeleteAll
a static member function with an explicit pointer argument:
/* static */ void Link::DeleteAll(Link* p) {
for (Link* q; p; p = q) {
q = p->next;
delete p;
}
}
The code is about the same length; the only difference in use is that
instead of saying
foo->DeleteAll();
you say
Link::DeleteAll(foo);
So I don't think this example is a particularly telling argument.
Ditto for the next example (omitted for brevity).
> Again, to reiterate (for Andrew's sake), I think it's a
> zero-cost feature; code that works now will continue to work,
It is not a zero-cost feature, because it would require compilers to
generate extra code for every call of a member function inherited
from a base class in the presence of virtual inheritance.
> and programmers who ignore it will be unaffected, i.e., if they
> don't check 'this' their programs will exhibit undefined
> behavior (by trying to access members) and "undefined behavior"
> is what happens now anyway.
The feature would prohibit C++ implementations from detecting this==0
as an error, which would make at least some genuine mistakes harder to find.
--
--Andrew Koenig
ark@europa.att.com
Re: this == 0 for nonvirtual functions
Author: Anders Juul Munch
Date: Tue, 25 Aug 1992 17:28
Date: Tue, 25 Aug 1992 17:28
29 lines
1460 bytes
1460 bytes
pjl@sparc10.cs.uiuc.edu (Paul Lucas) writes:
> void Link::DeleteAll() {
> for ( Link *p = this, *q; p; p = q ) {
> q = p->next;
> delete p;
> }
> }
You are deleting the first list member using its own DeleteAll method and
the other members using the first member's DeleteAll method.
To see what the problems can arise from this, make DeleteAll virtual and
redefine it in a subclass:
class MyLink : Link {
void DeleteAll() { ExtraBookkeeping(); Link::DeleteAll(); }
};
Now MyLink's will be DeleteAll'ed with the wrong method if a plain Link
heads the list. And to make things worse, such a bug would be almost
impossible to find.
However,
static Link::DeleteAll(Link* head);
does not have this problem and also note that `head' can legally be NULL,
solving your original problem.
Anders Munch | Department of Computer Science
juul@diku.dk | University of Copenhagen, Denmark
"Confused? The thing is to get confused at a higher level" - Jorgen Thorslund
Re: this == 0 for nonvirtual functions
Author: Jim Adcock
Date: Tue, 25 Aug 1992 19:22
Date: Tue, 25 Aug 1992 19:22
48 lines
3239 bytes
3239 bytes
In article <1992Aug21.044448.8282@sunb10.cs.uiuc.edu> pjl@sparc10.cs.uiuc.edu (Paul Lucas) writes: | If programmers elected not to check the this pointer, then the | program, if a member is accessed via a null-this, would most | likely crash or at least be undefined; this is _exactly_ the | way language is defined now; hence, for programmers who ignore | it, the (errant) behavior of their programs is unchanged. | | ***************************************************************** | Hence, adding my proposal changes nothing for those who ignore | it. | ***************************************************************** | | Again, all I want is the *call* to succeed; after that, I'm on | my own. The call already doesn't necessarily succeed in the virtual case. The call already doesn't necessarily succeed in the null-this-from-a-ref case. You are asking for support for a special case where a non-virtual member function is invoked via a null pointer. Asking for this singular special case seems awfully non-orthogonal to me. If you were to insist on this, then it should work for null-refs and for virtual functions.... | Perhaps [with regard to users checking null tests]; but I think | that one of the _themes_ of programming in C++ is to eliminate | tedium and errors introduced thereby: virtual functions | eliminate switch statements missing a case; exception-handling | will eliminate having to check the return value from new to see | if it failed, etc. | | I see my (modest) proposal in the same light. In the early days of Objective-C method invocation on a null pointer was defined to be a no-op. The result was intended to save programmers from having to handle special cases. In practice the result was that it took about a week to track down each case where some method was invoked on a null pointer -- because the result of such a mistake was a null pointer -- resulting in another no-op method call, resulting in a null pointer -- resulting in another no-op call. Fortunately, we had access to source and quickly patched the method dispatch routine so that invoking a method via a null pointer resulted instead in an assert. Then bugs were caught quickly. Therefore I suggest rather than allowing method invocation on null pointers what one really needs is a good way to always assert on such "mistakes." Allowing overloadable operator dot is one step in this direction. Further, defining null ptr invocations as being illegal *allows* quality compiler implementations the option of inserting runtime checks on such illegalities during debug mode. Better yet would be if C++ supported better ways to specify class invarients checking on method dispatch and return.
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads