Functions that don't use this, called with uninitialized pointers

39 views
Skip to first unread message

Andrei Alexandrescu

unread,
Jan 12, 1999, 3:00:00 AM1/12/99
to
Hello, the problem is simple:

class A {
int f(int i) { return i + 5; }
};

int main()
{
A * pA;
pA->f(1);
}

The question is, is the code guaranteed to work? Please refrain yourselves
from making comments on bad style etc. I've seen this in a test.

Thanks,

Andrei

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]

Francis Glassborow

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
In article <369b7...@10.1.1.65>, Andrei Alexandrescu <alexandrescua@mi
cromodeling.com> writes

>Hello, the problem is simple:
>
>class A {
> int f(int i) { return i + 5; }
>};
>
>int main()
>{
> A * pA;
> pA->f(1);
>}
>
>The question is, is the code guaranteed to work? Please refrain yourselves
>from making comments on bad style etc. I've seen this in a test.

It is guaranteed not to work. f() is a private member of A.

Now make it a public member and it still cannot work as f() is a member
function and requires a this value. You are now deep in undefined
territory.

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

Biju Thomas

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
Andrei Alexandrescu wrote:
>
> class A {
> int f(int i) { return i + 5; }
> };
> int main()
> {
> A * pA;
> pA->f(1);
> }
> The question is, is the code guaranteed to work?

No. It is undefined behaviour since a member function on an invalid
(uninitialized) object is invoked. It is equivalent to (*pA).f(1), and,
there is no object at (*pA).

But, it may work on many compilers as expected.

--
Regards,
Biju Thomas

Thiemo Seufer

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to

Andrei Alexandrescu wrote in message <369b7...@10.1.1.65>...

>Hello, the problem is simple:
>
>class A {
> int f(int i) { return i + 5; }
>};
>
>int main()
>{
> A * pA;
> pA->f(1);
>}
>
>The question is, is the code guaranteed to work? Please refrain yourselves
>from making comments on bad style etc. I've seen this in a test.


It's guaranteed NOT to work ( f() is not public :-)

Assuming public, I think the code will work (at least, I don't know why
it shouldn't) if it does not dereference 'this'.

No guarantees...

Thiemo Seufer

John Goodwin

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
On 13 Jan 1999 08:41:54 -0500, Biju Thomas <biju...@ibm.net> wrote:

>Andrei Alexandrescu wrote:
>>
>> class A {
>> int f(int i) { return i + 5; }
>> };
>> int main()
>> {
>> A * pA;
>> pA->f(1);
>> }
>> The question is, is the code guaranteed to work?
>

>No. It is undefined behaviour since a member function on an invalid
>(uninitialized) object is invoked. It is equivalent to (*pA).f(1), and,
>there is no object at (*pA).

It may be useful to consider it that way at a higher level, but most
ordercode processors would not in fact operate in that fashion.

The *call* to the member function above does not require a pointer.
True the uninitialisd pA will be passed (without dereferencing), but
since this is not used it's hard to see how it would cause an error.

I'd be interested to see if anyone can suggest how it could be
compiled to produce an error (assuming no debug code is introduced).

[This is not a defence of the technique of course]

JG

Antoun Kanawati

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
Andrei Alexandrescu wrote:
>
> Hello, the problem is simple:
>
> class A {
public:

> int f(int i) { return i + 5; }
> };
>
> int main()
> {
> A * pA;
> pA->f(1);
> }
>
> The question is, is the code guaranteed to work? Please refrain yourselves
> from making comments on bad style etc. I've seen this in a test.

Theoretically, you are invoking a member function on an undefined
entity,
therefore, the result of your action is undefined.

In practice, if your compiler is conventional (that is: no runtime
checks of any
sort :-), this will almost always work: the call is non-virtual, and
will be bound
at compile time; only the static type of (*pA) is involved, not the
contents.

Back in the "old days" (before static member functions), people used
NULL pointers
to invoke such member functions; e.g.: ((A *)0)->f().
--
Antoun Kanawati, akan...@bmc.com, to...@bgs.com
BMC Software, Inc., Waltham, MA, USA
DISCLAIMER: my opinions are mine, not the company's, etc...

Mungo Henning

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
Francis Glassborow wrote:
>
> In article <369b7...@10.1.1.65>, Andrei Alexandrescu
<alexandrescua@mi

I changed 'class' to 'struct' to circumvent the access problem:

> >struct A {


> > int f(int i) { return i + 5; }
> >};
> >
> >int main()
> >{
> > A * pA;
> > pA->f(1);
> >}
>

> Now make it a public member and it still cannot work as f() is a
member
> function and requires a this value. You are now deep in undefined
> territory.

Just how deep into undefined territory is the above code? Since the
(now)
struct is well defined, doesn't contain the keyword 'virtual', there's
no
derivation involved then when dealing with any pointer-to-A, if you
dereference
said pointer to call the function f() then there's only one possible
function
to call.

I'm sure that if you then added caveats such as derivation etc things
would become more difficult for the code, but as it stands what's the
problem?

Passing around "bad" pointers is acceptable, just as long as you don't
follow the pointer.
So is there any harm (apart from old-style cast) in:

((A*)0)->f(42);

Thanks in advance,

Mungo Henning

John Goodwin

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
On 13 Jan 1999 08:11:32 -0500, Francis Glassborow
<fra...@robinton.demon.co.uk> wrote:

>In article <369b7...@10.1.1.65>, Andrei Alexandrescu
<alexandrescua@mi

>cromodeling.com> writes


>>Hello, the problem is simple:
>>

>>class A {


>> int f(int i) { return i + 5; }
>>};
>>
>>int main()
>>{
>> A * pA;
>> pA->f(1);
>>}
>>

>>The question is, is the code guaranteed to work? Please refrain
yourselves
>>from making comments on bad style etc. I've seen this in a test.
>

>It is guaranteed not to work. f() is a private member of A.
>

>Now make it a public member and it still cannot work as f() is a member
>function and requires a this value. You are now deep in undefined
>territory.

Can you elaborate why you beleive it *cannot* work.

[It works perfectly on VC4.2 (after making f public)]

pA could contain *anything*, but since the "this" pointer is never
used, implicitly or explicitly, why should it fail?

JG

Larry Brasfield

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
Andrei Alexandrescu wrote in message <369b7...@10.1.1.65>...
>Hello, the problem is simple:
>
>class A {
> int f(int i) { return i + 5; }
>};
>
>int main()
>{
> A * pA;
> pA->f(1);
>}
>
>The question is, is the code guaranteed to work?

I don't think so. There is nothing to keep an implementation
from having some strange convention, say for handling virtual
functions, that requires all 'this' pointers to be found in a lookup
table prior to every member function call, whether the class
has virtual functions or not.

If you had asked "Will it usually work?", I would say "Sure."
But C++ does not constrain implementations to the common
memory/object model that was established so long ago.

>Please refrain yourselves
>from making comments on bad style etc. I've seen this in a test.

No, I cannot refrain myself. Nor is restraint called for.

It's not a matter of style. A member function that does
not do anything with the class instance upon which it
must be called is plain stupid. It is likely to be inefficient
and perplexing at the call site(s). Failing to declare it
static is a way of confounding the purpose of the function
that goes beyond mere style.

--Larry Brasfield
Above opinions may be mine alone.
(Humans may reply at unundered larry_br@sea_net.com )


.

Ziv Caspi

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
On 12 Jan 1999 14:42:05 -0500, "Andrei Alexandrescu"
<alexan...@micromodeling.com> wrote:

>Hello, the problem is simple:
>
>class A {

public:

> int f(int i) { return i + 5; }
>};
>
>int main()
>{
> A * pA;
> pA->f(1);
>}
>
>The question is, is the code guaranteed to work?

No. pA is not initialized. Using it is undefined behavior.

---------------------------------------------
Ziv Caspi
zi...@netvision.net.il

John Duncan

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to

The behavior is implementation dependant, assuming that
it is made public as everyone else has mentioned. I don't
believe that there is any requirement that the proper
method binding be created for a never-constructed object.
One can statically determine the existence of a ctor call
by looking for

(1) an automatic allocation of the object,
(2) a use of the class name as an argument to operator new.

Chances are good that it will work. Here's my modified
version:

// test.cpp--
#include <iostream.h>

struct A {


int f(int i) { return i + 5; }
};

int main()
{
A * pA;

cout << (pA->f(1));
return 0;
}
// end test.cpp

and my shell session with Visual C++ 6.

C:\Projects\MSVC\test>cl test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for
80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

test.cpp
test.cpp(10) : warning C4700: local variable 'pA' used without having
been
initi
alized
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:test.exe
test.obj

C:\Projects\MSVC\test>test
6

C:\Projects\MSVC\test>

BUT, if you paid me for the work, I could probably write a standard-
compliant modification of GCC whose output barfed on this.

-John

Siemel Naran

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
On 12 Jan 1999 14:42:05 -0500, Andrei Alexandrescu

>class A {


> int f(int i) { return i + 5; }
>};
>
>int main()
>{
> A * pA;

> pA->f(1);
>}
>
>The question is, is the code guaranteed to work? Please refrain yourselves


>from making comments on bad style etc. I've seen this in a test.

No, it's not guaranteed. On most implementations, A::f() becomes
int f(A *const this, int i) { return i+5; }
But an implementation is free to add "assert(this)" at the head of
each function.

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

David Kastrup

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:

> Hello, the problem is simple:
>

> class A {
> int f(int i) { return i + 5; }
> };
>
> int main()
> {
> A * pA;
> pA->f(1);
> }
>
> The question is, is the code guaranteed to work?

No. It would be legal if f were a static member function.

--
David Kastrup Phone: +49-234-700-5570
Email: d...@neuroinformatik.ruhr-uni-bochum.de Fax: +49-234-709-4209
Institut für Neuroinformatik, Universitätsstr. 150, 44780 Bochum, Germany

Steve Clamage

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:

>Hello, the problem is simple:

>class A {
> int f(int i) { return i + 5; }
>};

>int main()
>{
> A * pA;
> pA->f(1);
>}

>The question is, is the code guaranteed to work? Please refrain yourselves


>from making comments on bad style etc. I've seen this in a test.

Auto variale pA is not initialized, but must be dereferenced
to call the non-static member function f. The results of the program
are undefined by the standard, meaning anything at all might happen.

A helpful compiler will complain about using an uninitialized
variable, and is within its rights to refuse to compile the
program at all.

Some runtime systems cause uninitialized variables to have values
that result in a run-time trap if accessed before being set. On
such a system the program would abort at run time, if the compiler
accepted the code in the first place.

--
Steve Clamage, stephen...@sun.com

Rolf F. Katzenberger

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
On 12 Jan 1999 14:42:05 -0500, in article <369b7...@10.1.1.65> "Andrei
Alexandrescu" <alexan...@micromodeling.com> wrote:

> Hello, the problem is simple:
>
> class A {
> int f(int i) { return i + 5; }

f isn't public.

> };

A has no public constructor.

> int main()
> {
> A * pA;

pA isn't pointing to an A.

> pA->f(1);
> }
>
> The question is, is the code guaranteed to work?

It doesn't even compile before you make f() public.


Regards,
Rolf


--
______________________________________________________________________
Rolf F. Katzenberger | Software Developer | Trainer 1998-11-18
Home: http://www.geocities.com/SiliconValley/Park/9557
PGP : http://wwwkeys.pgp.net:11371/pks/lookup?op=get&search=0x3B39491F

Francis Glassborow

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
In article <369CA688...@itacs.strath.ac.uk>, Mungo Henning
<mun...@itacs.strath.ac.uk> writes
>> >struct A {

>> > int f(int i) { return i + 5; }
>> >};

>> >
>> >int main()
>> >{
>> > A * pA;
>> > pA->f(1);

>> >}
>>
>> Now make it a public member and it still cannot work as f() is a
>member
>> function and requires a this value. You are now deep in undefined
>> territory.
>
>Just how deep into undefined territory is the above code? Since the
>(now)
>struct is well defined, doesn't contain the keyword 'virtual', there's
>no
>derivation involved then when dealing with any pointer-to-A, if you
>dereference
>said pointer to call the function f() then there's only one possible
>function
>to call.

When the function call is made, two arguments are forwarded to f(). One
of those is a pointer (the value in pA). If that pointer is invalid (is
outside the range of pointers -addresses- available to your program at
the time of execution of that statement) you have undefined behaviour.
Quite a few platforms may abort your process with a segment violation
fault.

To argue that the compiler will optimise away all the problems is just
asking for trouble. One day that f() will be changed with disastrous
consequences. I believe that writing unnecessarily flaky code is
unprofessional.

Guideline:

Do not write member functions that do not use any characteristic of the
class (one reason namespaces were invented was to make this completely
unnecessary)

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Jean-Francois Brouillet

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
{ Please quote moderately! -vdv }
----------
>From: J...@opticon.demon.co.uk (John Goodwin)
>Newsgroups: comp.lang.c++.moderated
>Subject: Re: Functions that don't use this, called with uninitialized pointers
>Date: Wed, Jan 13, 1999, 18:02
>

> On 13 Jan 1999 08:11:32 -0500, Francis Glassborow
> <fra...@robinton.demon.co.uk> wrote:
>
>>In article <369b7...@10.1.1.65>, Andrei Alexandrescu
> <alexandrescua@mi
>>cromodeling.com> writes

>>>Hello, the problem is simple:
>>>

>>>class A {


>>> int f(int i) { return i + 5; }
>>>};
>>>
>>>int main()
>>>{
>>> A * pA;
>>> pA->f(1);
>>>}
>>>

>>>The question is, is the code guaranteed to work? Please refrain
> yourselves
>>>from making comments on bad style etc. I've seen this in a test.
>>

>>It is guaranteed not to work. f() is a private member of A.
>>

>>Now make it a public member and it still cannot work as f() is a member
>>function and requires a this value. You are now deep in undefined
>>territory.
>

> Can you elaborate why you beleive it *cannot* work.
>
> [It works perfectly on VC4.2 (after making f public)]
>
> pA could contain *anything*, but since the "this" pointer is never
> used, implicitly or explicitly, why should it fail?

Consider first a slight modification...

class aa {
// empty
} ;

class A : public aa {
// rest same as above
} ;

Does this change the nature of the question ?

Now consider a slight variation:

class aa {
public:
virtual int f(int i) ;

} ;

class A : public aa {
// rest same as above
} ;


Now, is the usual "but why should it fail" so obvious ?

--
jean-franco...@virgin.net

mar...@my-dejanews.com

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
In article <369c9f6c....@news.demon.co.uk>,

J...@opticon.demon.co.uk (John Goodwin) wrote:
> On 13 Jan 1999 08:41:54 -0500, Biju Thomas <biju...@ibm.net> wrote:
>
> >Andrei Alexandrescu wrote:
> >>
> >> class A {
> >> int f(int i) { return i + 5; }
> >> };
> >> int main()
> >> {
> >> A * pA;
> >> pA->f(1);
> >> }
> >> The question is, is the code guaranteed to work?
> >
> >No. It is undefined behaviour since a member function on an invalid
> >(uninitialized) object is invoked. It is equivalent to (*pA).f(1), and,
> >there is no object at (*pA).
>
> It may be useful to consider it that way at a higher level, but most
> ordercode processors would not in fact operate in that fashion.
>
> The *call* to the member function above does not require a pointer.
> True the uninitialisd pA will be passed (without dereferencing), but
> since this is not used it's hard to see how it would cause an error.
>
> I'd be interested to see if anyone can suggest how it could be
> compiled to produce an error (assuming no debug code is introduced).
>
I know of at least one compiler that will generate code that will fail.

The old microsoft 16 bit compiler had an option to pass the 'this' pointer in
registers. If you compiled in "far" mode, that meant loading the high bits of
the address into ES. On the x86, just *loading* an invalid value into a
segment register causes a runtime exception - it doesnt wait until you *use*
it. So the above code would (most likely) fail.

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Francis Glassborow

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
In article <369c9f6c....@news.demon.co.uk>, John Goodwin
<J...@opticon.demon.co.uk> writes

>>Andrei Alexandrescu wrote:
>>>
>>> class A {
>>> int f(int i) { return i + 5; }
>>> };
>>> int main()
>>> {
>>> A * pA;
>>> pA->f(1);
>>> }
>>> The question is, is the code guaranteed to work?
>>
>>No. It is undefined behaviour since a member function on an invalid
>>(uninitialized) object is invoked. It is equivalent to (*pA).f(1), and,
>>there is no object at (*pA).
>
>It may be useful to consider it that way at a higher level, but most
>ordercode processors would not in fact operate in that fashion.
>The *call* to the member function above does not require a pointer.
>True the uninitialisd pA will be passed (without dereferencing), but
>since this is not used it's hard to see how it would cause an error.
>
>I'd be interested to see if anyone can suggest how it could be
>compiled to produce an error (assuming no debug code is introduced).

The type of f is pointer to member taking an int and returning an int.
Without optimisation:

the code must dereference f (that is the way functions work) to obtain
the location of f, the arguments for the call (this and a temp int with
value 1) placed for transfer. At this stage you have a wild pointer
floating around.

The very fact that even the simplest compiler circumvents this is what
makes writing code so very dangerous. Its working relies entirely on
several fortuitous circumstances (non-virtual function, makes no access
to member data etc.)

I do not believe that any programmer would actually write such code as a
permanent feature. It has a distinct feel of being a place holder.

Put it another way, the code may 'work' on most compilers but any team
leader that allowed code like that out of the door would have to work
very hard to remain in work:) in a respectable software shop.


Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
In article <369c9a19....@news.demon.co.uk>, John Goodwin
<J...@opticon.demon.co.uk> writes

>Can you elaborate why you beleive it *cannot* work.

Sorry, when I say cannot work, I mean reliably whatever is later added
to the implementation. In particular accessing any data member of A
will cause potentially catestrophic failure.

>
>[It works perfectly on VC4.2 (after making f public)]


>
>pA could contain *anything*, but since the "this" pointer is never
>used, implicitly or explicitly, why should it fail?

It is 'used' (technical term defined somewhere in the standard),
because it is passed as an argument to f().

Alex Martelli

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
Larry Brasfield wrote in message
[snip]

>It's not a matter of style. A member function that does
>not do anything with the class instance upon which it
>must be called is plain stupid. It is likely to be inefficient
>and perplexing at the call site(s). Failing to declare it
>static is a way of confounding the purpose of the function
>that goes beyond mere style.


Personally, I rate it just about on a par with any
other function that does not use all of the parameters
that are passed to it (and C++ even includes an
extension to C to facilitate other cases of such
functions, i.e. unnamed parameters): i.e., pretty
normal in evolving code. Perhaps the function does
not use the parameter TODAY, but it used to, and
maybe will again -- meanwhile, one keeps the
parameter there; why make all clients recompile?!
Not a very strong issue, but a frequent one.

Or perhaps, and this is a perfectly reasonable case
that also applies to completely stable code!, there
is a pointer-to-member somewhere, that must be
able to point to this function, or alternatively to
others; it is then quite reasonable to supply this
function with extra arguments it will not use (and
this includes the "this" pointer!), to "extend", so
to speak, its signature to that of the other functions
it must be interchangeable with. This may not be
a very frequent case, but it IS a very strong
argument for asserting that "plain stupid" is a
very unwise judgment to make for this idiom.

None of this has anything to do with calling a
function through an uninitialized pointer, which
is and remains undefined behaviour, whether the
function "uses" the this pointer or not.


Alex

-----------== Posted via Newsfeeds.Com, Uncensored Usenet News ==----------
http://www.newsfeeds.com/ The Largest Usenet Servers in the World!
-----------== Over 66,000 Groups, Plus a Dedicated Binaries Server
==----------

Steve Clamage

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
J...@opticon.demon.co.uk (John Goodwin) writes:

>On 13 Jan 1999 08:41:54 -0500, Biju Thomas <biju...@ibm.net> wrote:

>>Andrei Alexandrescu wrote:
>>>
>>> class A {
>>> int f(int i) { return i + 5; }
>>> };
>>> int main()
>>> {
>>> A * pA;
>>> pA->f(1);
>>> }
>>> The question is, is the code guaranteed to work?
>>
>>No. It is undefined behaviour since a member function on an invalid
>>(uninitialized) object is invoked. It is equivalent to (*pA).f(1), and,
>>there is no object at (*pA).

>It may be useful to consider it that way at a higher level, but most
>ordercode processors would not in fact operate in that fashion.

>The *call* to the member function above does not require a pointer.
>True the uninitialisd pA will be passed (without dereferencing), but
>since this is not used it's hard to see how it would cause an error.

>I'd be interested to see if anyone can suggest how it could be
>compiled to produce an error (assuming no debug code is introduced).

On a tagged architecture, attempting to read a pointer value that
is not valid results in a runtime trap that will by default abort
the program. It is not necessary to dereference the pointer to get
a trap; attempting to read the value is enough.

A pointer-checking C++ runtime system could have the same behavior.

The original question was whether the code was guaranteed to
work. Any expression of the forms
p->data_member
p->func_member()
whether static or nonstatic data or function members, has undefined
behavior unless p points to an object of the appropriate type.

Even when accessing a static member, the standard requires that
the object-expression to the left of the "->" be evaluated, and
"a->b" is defined to mean the same thing as "(*a).b".

Undefined behavior means that there are no guarantees.

--
Steve Clamage, stephen...@sun.com

Biju Thomas

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
Rolf F. Katzenberger wrote:
>
> On 12 Jan 1999 14:42:05 -0500, in article <369b7...@10.1.1.65> "Andrei
> Alexandrescu" <alexan...@micromodeling.com> wrote:
>
> >
> > class A {
> > int f(int i) { return i + 5; }
> > };
>
> A has no public constructor.
>

That is not true. The default constructor (provided by the compiler) is
public. Otherwise, what is the use of default constructor?

--
Regards,
Biju Thomas

Andrew Koenig

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
In article <369c9f6c....@news.demon.co.uk>,
John Goodwin <J...@opticon.demon.co.uk> wrote:

> I'd be interested to see if anyone can suggest how it could be
> compiled to produce an error (assuming no debug code is introduced).

Easy. Imagine a machine with separate address and data registers,
with the address registers having the property that putting an address
into an address register causes virtual-memory translation to occur
immediately. Imagine further a compiler whose calling sequence for
member functions involves putting the value of `this' into one of
these address registers

Then the caller might put the invalid address into the register intended
to contain `this,' on the assumption that the callee will use it,
and the virtual-memory translation might cause a trap at that point,
even though the callee never actually uses the address.

It's the same kind of logic that prohibits the following:

int* p1 = new int;
int* p2 = p1;
delete p1;
int* p3 = p2; // undefined behavior

Although "delete p1" could not have changed the value of p2, the fact
that p2 pointed to memory that has been deleted means that the value of
p2 cannot even be copied, whether or not any overt attempt is made to
dereference p2.
--
Andrew Koenig
a...@research.att.com
http://www.research.att.com/info/ark

John Goodwin

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
On 13 Jan 1999 13:01:49 -0500, Mungo Henning
<mun...@itacs.strath.ac.uk> wrote:

snip

>Passing around "bad" pointers is acceptable, just as long as you don't
>follow the pointer.

Passing "bad" pointers may work, but it's hardly "acceptable". That
bad pointer might get passed on, and eventualy, many months hence used
by another programmer.

Murphy's law states that it would then work until the shrink wraps had
been manufactured.

JG

Alex Martelli

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
John Goodwin wrote in message <369c9a19....@news.demon.co.uk>...
[snip]

>Can you elaborate why you beleive it *cannot* work.
>
>[It works perfectly on VC4.2 (after making f public)]
>
>pA could contain *anything*, but since the "this" pointer is never
>used, implicitly or explicitly, why should it fail?


"undefined behaviour" means that anything and everything can
happen, and calling pA->f() with pA uninitialized invokes
undefined behaviour. On some hardware, for example,
the calling convention could involve loading pA into a hardware
register, and such a load could implicitly and automatically
cause a check of pointer validity, with program termination
if the check fails; perfectly reasonable behaviour, on suitable
hardware, since the language _does_ allow the compiler to
assume pA is valid when pA->f() is called.

In general, it is rather pointless to speculate on exactly what
"undefined behaviour" could mean, and why -- it is by far
wiser to simply eschew causing it, even if a given release of
a given compiler should appear, on a small sample of tests,
not too react too badly.


Alex

-----------== Posted via Newsfeeds.Com, Uncensored Usenet News
==----------
http://www.newsfeeds.com/ The Largest Usenet Servers in the
World!
-----------== Over 66,000 Groups, Plus a Dedicated Binaries Server
==----------

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

John Goodwin

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
On 14 Jan 1999 00:19:32 -0500, Francis Glassborow
<fra...@robinton.demon.co.uk> wrote:

>In article <369c9a19....@news.demon.co.uk>, John Goodwin
><J...@opticon.demon.co.uk> writes

snip

>>pA could contain *anything*, but since the "this" pointer is never
>>used, implicitly or explicitly, why should it fail?
>

>It is 'used' (technical term defined somewhere in the standard),
>because it is passed as an argument to f().
>

I was using "used" in the sense of "used by the ordercode processor",
and none of those yet understand the standard :)

JG

John Goodwin

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
On 14 Jan 1999 00:21:32 -0500, mar...@my-dejanews.com wrote:

snip

>> I'd be interested to see if anyone can suggest how it could be
>> compiled to produce an error (assuming no debug code is introduced).
>>

>I know of at least one compiler that will generate code that will fail.
>
>The old microsoft 16 bit compiler had an option to pass the 'this'
pointer in
>registers. If you compiled in "far" mode, that meant loading the high
bits of
>the address into ES. On the x86, just *loading* an invalid value into a
>segment register causes a runtime exception - it doesnt wait until you
*use*
>it. So the above code would (most likely) fail.

Thanks for that. I had a feeling it might happen on some machine with
a weird and wonderful instruction set. Mind you that x86 segment
kludge is pretty weird*!

JG

* Joke

John Goodwin

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
On 14 Jan 1999 00:17:33 -0500, Francis Glassborow
<fra...@robinton.demon.co.uk> wrote:

>In article <369c9f6c....@news.demon.co.uk>, John Goodwin
><J...@opticon.demon.co.uk> writes


>>>Andrei Alexandrescu wrote:
>>>>
>>>> class A {
>>>> int f(int i) { return i + 5; }
>>>> };

>>>> int main()
>>>> {
>>>> A * pA;
>>>> pA->f(1);
>>>> }
>>>> The question is, is the code guaranteed to work?
>>>
>>>No. It is undefined behaviour since a member function on an invalid
>>>(uninitialized) object is invoked. It is equivalent to (*pA).f(1),
and,
>>>there is no object at (*pA).
>>
>>It may be useful to consider it that way at a higher level, but most
>>ordercode processors would not in fact operate in that fashion.
>>The *call* to the member function above does not require a pointer.
>>True the uninitialisd pA will be passed (without dereferencing), but
>>since this is not used it's hard to see how it would cause an error.
>>

>>I'd be interested to see if anyone can suggest how it could be
>>compiled to produce an error (assuming no debug code is introduced).
>

>The type of f is pointer to member taking an int and returning an int.

Agreed.

>Without optimisation:
>
>the code must dereference f (that is the way functions work) to obtain
>the location of f,

Only if you consider placing a literal value in the IP register to be
dereferencing !

> the arguments for the call (this and a temp int with
>value 1) placed for transfer. At this stage you have a wild pointer
>floating around.

Agreed.

>The very fact that even the simplest compiler circumvents this is what
>makes writing code so very dangerous.

Again, agreed. Of course, a decent development compiler would complain
about the use of an uninitialised variable, but not all are that
forthcoming :(

>Its working relies entirely on
>several fortuitous circumstances (non-virtual function, makes no access
>to member data etc.)

Yes, and in the example given (which is what we were discussing), all
the circumstances to the left of etc. do indeed hold.

>I do not believe that any programmer would actually write such code as
a
>permanent feature. It has a distinct feel of being a place holder.

Agreed.

>Put it another way, the code may 'work' on most compilers but any team
>leader that allowed code like that out of the door would have to work
>very hard to remain in work:) in a respectable software shop.

Agreed, which is why I said:

|[This is not a defence of the technique of course]

JG

John Goodwin

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
On 13 Jan 1999 20:43:30 -0500, cla...@Eng.Sun.COM (Steve Clamage)
wrote:

>"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:
>
>>Hello, the problem is simple:
>

>>class A {
>> int f(int i) { return i + 5; }
>>};
>
>>int main()
>>{
>> A * pA;
>> pA->f(1);
>>}
>

>>The question is, is the code guaranteed to work? Please refrain
yourselves
>>from making comments on bad style etc. I've seen this in a test.
>

>Auto variale pA is not initialized, but must be dereferenced
>to call the non-static member function f.

Am I (and my colleagues) at odds with the general concensus on what
constitutes a dereference?

I cannot see any reason why, in this case, the pointer needs to be
dereferenced to obey the code.

It is not needed for the call instruction, and even if the "this"
pointer is passed, it should not be dereferenced in the passing
process, and is not used in the function.

John Goodwin

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
On 14 Jan 1999 06:37:09 -0500, cla...@Eng.Sun.COM (Steve Clamage)
wrote:

snip

>The original question was whether the code was guaranteed to
>work. Any expression of the forms
> p->data_member
> p->func_member()
>whether static or nonstatic data or function members, has undefined
>behavior unless p points to an object of the appropriate type.
>
>Even when accessing a static member, the standard requires that
>the object-expression to the left of the "->" be evaluated,

Can you explain *exactly* what you mean by "evaluated" ?

Are you saying that the standard says that a compiler is obliged to
insert redundant code to perfom some spurious "evaluation" ?

That would be a *very* odd requirement. Indeed, I can't imagine anyone
ever producing a compliant optimising compiler for the x86
architecture if that is the case.

> and
>"a->b" is defined to mean the same thing as "(*a).b".
>
>Undefined behavior means that there are no guarantees.

I hope you didn't think I was arguing that there were!

Valentin Bonnard

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
David Kastrup wrote:
>
> "Andrei Alexandrescu" <alexan...@micromodeling.com> writes:
>
> > Hello, the problem is simple:
> >
> > class A {
> > int f(int i) { return i + 5; }
> > };
> >
> > int main()
> > {
> > A * pA;
> > pA->f(1);
> > }
> >
> > The question is, is the code guaranteed to work?
>
> No. It would be legal if f were a static member function.

It used to be legal, but now the object has to be evaluted
even with a static function: fun()->static_member has to
call fun(). So the behaviour would be undefined as well.

--

Valentin Bonnard mailto:bonn...@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/

Valentin Bonnard

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
John Goodwin wrote:
>
> On 13 Jan 1999 20:43:30 -0500, cla...@Eng.Sun.COM (Steve Clamage)
> wrote:
>
> >"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:

> >> A * pA;
> >> pA->f(1);

> >>The question is, is the code guaranteed to work? Please refrain


> >>yourselves
> >>from making comments on bad style etc. I've seen this in a test.

> >Auto variale pA is not initialized, but must be dereferenced
> >to call the non-static member function f.
>
> Am I (and my colleagues) at odds with the general concensus on what
> constitutes a dereference?

It isn't a consensus, it's a definition.

pointer->member means (*pointer).member. Isn't * usally called the
dereferencement operator ?

(It might run w/o crashing your computer, or w/o reformating your
hard disk. But remember: it's undefined behaviour.)

Francis Glassborow

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
In article <369dd35d....@news.demon.co.uk>, John Goodwin
<J...@opticon.demon.co.uk> writes

>Am I (and my colleagues) at odds with the general concensus on what
>constitutes a dereference?
>
>I cannot see any reason why, in this case, the pointer needs to be
>dereferenced to obey the code.

dereferenced may be too strong a term, and in this case we even have an
in class definition that the compiler can see however the compiler is
not required to take any notice (indeed some compilers have switches to
turn of inlining) therefore we must assume that the value of pA is
passed to 'this'. That value may well be passed in an (address)
register and protected memory systems will often be set to abort any
program that loads an invalid address into an address register without
any regard to how you intend to use it. That action is taken by the
OS/hardware and is beyond the control of your compiler.

>
>It is not needed for the call instruction, and even if the "this"
>pointer is passed, it should not be dereferenced in the passing
>process, and is not used in the function.

Oh, and the standard, I believe, requires that the expression to the
left of '.' and '->' be evaluated (though the as-if rule applies)

Finally, the compiler is not prohibited from dereferencing that pointer.
For example, imagine some (debugging) implementation that always
accessed member functions through a jump table regardless as to whether
the functions were or were not virtual (I would be interested if anyone
can pin down a standard requirement that prohibits this) then pA would
be dereferenced.

A line of code that always exhibits unpredictable behaviour is quickly
located. One that has apparently run without problems for many months
is much more problematical. This is what I meant when I originally
wrote that 'deep in undefined behaviour'

What interested me was to realise that the method in question was what
was used before class statics were invented. That leads me to suspect
that the writer of the test question that started this thread may have
been in time stasis (I do not have a copy 'The C++ Programming Language
1st edition any longer -- Sorry Bjarne but my book shelves lack dynamic
resources) but were class statics already in C++ at that stage?

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Hyman Rosen

unread,
Jan 14, 1999, 3:00:00 AM1/14/99
to
John Goodwin wrote:
> Am I (and my colleagues) at odds with the general concensus on what
> constitutes a dereference?

Yes. What you are trying to do involves "logical dereference" - that is,
you are attempting to call a member function of an object, and the
language
standard requires that the object be valid, or the results are
undefined.

What you are trying to do is hackery - that is, you are relying on
knowledge
of specific implementation behavior on specific platforms which tells
you
that
in this particular case, the code will behave as you want it to.

This leaves you open to two problems. One, if you port the code to a
different
platform, including upgrades of your current one, the code may stop
working.
Two, if you modify your code in any way, you might invalidate the
assumptions
that allowed the hack to esacpe unpunished, and again it might stop
working.

For example, if I were working on a compiler, I might decide to
implement
an
optimization, such that when flow-analysis tells me that an operation
would
produce undefined results, I simply remove the entire operation.

jim.h...@leitch.com

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
In article <slrn79nabh....@localhost.localdomain>,
sbn...@uiuc.edu wrote:
> On 12 Jan 1999 14:42:05 -0500, Andrei Alexandrescu

>
> >class A {
> > int f(int i) { return i + 5; }
> >};
> >
> >int main()
> >{
> > A * pA;
> > pA->f(1);
> >}
> >
> >The question is, is the code guaranteed to work? Please refrain yourselves
> >from making comments on bad style etc. I've seen this in a test.
>
> No, it's not guaranteed. On most implementations, A::f() becomes
> int f(A *const this, int i) { return i+5; }
> But an implementation is free to add "assert(this)" at the head of
> each function.
Hmm... I presume your "assert(this)" is meant to illustrate some kind of error
trapping, something like "assert(isValid(this))" where isValid() is some
implementation-defined function that checks the validity of a pointer.

A literal 'assert(this)' has about a 1 in 4 billion chance of catching an
uninitialized pointer, since only the value 0 will cause the statement to
fail (assuming, of course, that the value at pA contains a statistically
random value). Any other non-zero value will not cause an assertion.
Considering that assert() is only active in debug builds, and considering
further that some implementations may actually zero-initialize variables for
debug builds, then the chances of a literal assert(this) actually working are
reduced considerably :-)

Jim
Note to recruitment agencies: I delete unsolicited email from
recruitment agencies without reading it, so don't even bother.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Steve Clamage

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
David Kastrup <d...@fsnif.neuroinformatik.ruhr-uni-bochum.de> writes:

>"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:

>> Hello, the problem is simple:
>>

>> class A {
>> int f(int i) { return i + 5; }
>> };
>>
>> int main()
>> {
>> A * pA;
>> pA->f(1);
>> }
>>
>> The question is, is the code guaranteed to work?

>No. It would be legal if f were a static member function.

It would legal according to the ARM but not according to the
standard.

The ARM said the the object-expression to the left of a "."
or "->" was not evaluated when accessing a static member.

The standard says the object-expression is always evaluated,
even when accessing a static member.

--
Steve Clamage, stephen...@sun.com

Steve Clamage

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
J...@opticon.demon.co.uk (John Goodwin) writes:

>On 14 Jan 1999 06:37:09 -0500, cla...@Eng.Sun.COM (Steve Clamage)
>wrote:

>>The original question was whether the code was guaranteed to


>>work. Any expression of the forms
>> p->data_member
>> p->func_member()
>>whether static or nonstatic data or function members, has undefined
>>behavior unless p points to an object of the appropriate type.
>>
>>Even when accessing a static member, the standard requires that
>>the object-expression to the left of the "->" be evaluated,

>Can you explain *exactly* what you mean by "evaluated" ?

>Are you saying that the standard says that a compiler is obliged to
>insert redundant code to perfom some spurious "evaluation" ?

The C++ standard describes the behavior of an abstract machine.
As explained in chapter 1 of the standard, a C++ implementation
is obliged to get the same observable behavior produced by the
abstract machine for a program whose behavior is defined. The
compiler is allowed to optimize away unnecessary code that does not
affect the observable behavior. ("Observable behavior" is another
technical term. It means calls to library I/O functions, and reads
and writes of volatile data.)

The abstract machine evaluates the left side of a member access
expression. If those results are undefined, as they are in the
case in question, the standard places no requirements on the
behavior of the C++ implementation.

Bjarne Stroustrup

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to

Francis Glassborow <fra...@robinton.demon.co.uk> writes:

> (I do not have a copy 'The C++ Programming Language
> 1st edition any longer -- Sorry Bjarne but my book shelves lack dynamic
> resources) but were class statics already in C++ at that stage?

Static data members were in Release 1 of C++, and they weren't new
then :-) They are described in section 5.5.2 of the first edition of
"The C++ Programming Language". Static member functions were added a
couple of years later in release 2.0 (and Francis, you could have
found that factoid in "The Design and Evolution of C++." I'm pretty
sure D&E hasn't fallen off the end of your shelf :-).

- Bjarne
Bjarne Stroustrup - http://www.research.att.com/~bs

Larry Brasfield

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
Andrei Alexandrescu wrote in message <369b7...@10.1.1.65>...

>Hello, the problem is simple:
>
>class A {
> int f(int i) { return i + 5; }
>};
>
>int main()
>{
> A * pA;
> pA->f(1);
>}
>
>The question is, is the code guaranteed to work?

I don't think so. There is nothing to keep an implementation
from having some strange convention, say for handling virtual
functions, that requires all 'this' pointers to be found in a lookup
table prior to every member function call, whether the class
has virtual functions or not.

If you had asked "Will it usually work?", I would say "Sure."
But C++ does not constrain implementations to the common
memory/object model that was established so long ago.

>Please refrain yourselves
>from making comments on bad style etc. I've seen this in a test.

No, I cannot refrain myself. Nor is restraint called for.

It's not a matter of style. A member function that does
not do anything with the class instance upon which it
must be called is plain stupid. It is likely to be inefficient
and perplexing at the call site(s). Failing to declare it
static is a way of confounding the purpose of the function
that goes beyond mere style.

--Larry Brasfield
Above opinions may be mine alone.
(Humans may reply at unundered larry_br@sea_net.com )


.

John Goodwin

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
On 13 Jan 1999 08:11:32 -0500, Francis Glassborow
<fra...@robinton.demon.co.uk> wrote:

>In article <369b7...@10.1.1.65>, Andrei Alexandrescu
<alexandrescua@mi
>cromodeling.com> writes

>>Hello, the problem is simple:
>>
>>class A {
>> int f(int i) { return i + 5; }
>>};
>>
>>int main()
>>{
>> A * pA;
>> pA->f(1);
>>}
>>

>>The question is, is the code guaranteed to work? Please refrain


yourselves
>>from making comments on bad style etc. I've seen this in a test.
>

>It is guaranteed not to work. f() is a private member of A.
>
>Now make it a public member and it still cannot work as f() is a member
>function and requires a this value. You are now deep in undefined
>territory.

Can you elaborate why you beleive it *cannot* work.

[It works perfectly on VC4.2 (after making f public)]

pA could contain *anything*, but since the "this" pointer is never


used, implicitly or explicitly, why should it fail?

JG

Ziv Caspi

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
On 12 Jan 1999 14:42:05 -0500, "Andrei Alexandrescu"
<alexan...@micromodeling.com> wrote:

>Hello, the problem is simple:
>
>class A {

public:

> int f(int i) { return i + 5; }
>};
>
>int main()
>{
> A * pA;
> pA->f(1);
>}
>
>The question is, is the code guaranteed to work?

No. pA is not initialized. Using it is undefined behavior.

---------------------------------------------
Ziv Caspi
zi...@netvision.net.il

John Duncan

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to

The behavior is implementation dependant, assuming that
it is made public as everyone else has mentioned. I don't
believe that there is any requirement that the proper
method binding be created for a never-constructed object.
One can statically determine the existence of a ctor call
by looking for

(1) an automatic allocation of the object,
(2) a use of the class name as an argument to operator new.

Chances are good that it will work. Here's my modified
version:

// test.cpp--
#include <iostream.h>

struct A {


int f(int i) { return i + 5; }
};

int main()
{
A * pA;

cout << (pA->f(1));
return 0;
}
// end test.cpp

and my shell session with Visual C++ 6.

C:\Projects\MSVC\test>cl test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for
80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.

test.cpp
test.cpp(10) : warning C4700: local variable 'pA' used without having
been
initi
alized
Microsoft (R) Incremental Linker Version 6.00.8168
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.

/out:test.exe
test.obj

C:\Projects\MSVC\test>test
6

C:\Projects\MSVC\test>

BUT, if you paid me for the work, I could probably write a standard-
compliant modification of GCC whose output barfed on this.

-John

Siemel Naran

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
On 12 Jan 1999 14:42:05 -0500, Andrei Alexandrescu

>class A {


> int f(int i) { return i + 5; }
>};
>
>int main()
>{
> A * pA;

> pA->f(1);
>}
>


>The question is, is the code guaranteed to work? Please refrain yourselves
>from making comments on bad style etc. I've seen this in a test.

No, it's not guaranteed. On most implementations, A::f() becomes


int f(A *const this, int i) { return i+5; }
But an implementation is free to add "assert(this)" at the head of
each function.

--
----------------------------------
Siemel B. Naran (sbn...@uiuc.edu)
----------------------------------

David Kastrup

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:

> Hello, the problem is simple:
>

> class A {
> int f(int i) { return i + 5; }
> };
>
> int main()
> {
> A * pA;
> pA->f(1);
> }
>
> The question is, is the code guaranteed to work?

No. It would be legal if f were a static member function.

--
David Kastrup Phone: +49-234-700-5570
Email: d...@neuroinformatik.ruhr-uni-bochum.de Fax: +49-234-709-4209
Institut für Neuroinformatik, Universitätsstr. 150, 44780 Bochum, Germany

Mungo Henning

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
Francis Glassborow wrote:
>
> In article <369b7...@10.1.1.65>, Andrei Alexandrescu
<alexandrescua@mi

I changed 'class' to 'struct' to circumvent the access problem:

> >struct A {


> > int f(int i) { return i + 5; }
> >};
> >
> >int main()
> >{
> > A * pA;
> > pA->f(1);
> >}
>

> Now make it a public member and it still cannot work as f() is a
member
> function and requires a this value. You are now deep in undefined
> territory.

Just how deep into undefined territory is the above code? Since the
(now)
struct is well defined, doesn't contain the keyword 'virtual', there's
no
derivation involved then when dealing with any pointer-to-A, if you
dereference
said pointer to call the function f() then there's only one possible
function
to call.

I'm sure that if you then added caveats such as derivation etc things
would become more difficult for the code, but as it stands what's the
problem?

Passing around "bad" pointers is acceptable, just as long as you don't
follow the pointer.

So is there any harm (apart from old-style cast) in:

((A*)0)->f(42);

Thanks in advance,

Mungo Henning

Francis Glassborow

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
In article <369CA688...@itacs.strath.ac.uk>, Mungo Henning
<mun...@itacs.strath.ac.uk> writes

>> >struct A {
>> > int f(int i) { return i + 5; }
>> >};
>> >
>> >int main()
>> >{
>> > A * pA;
>> > pA->f(1);
>> >}
>>
>> Now make it a public member and it still cannot work as f() is a
>member
>> function and requires a this value. You are now deep in undefined
>> territory.
>
>Just how deep into undefined territory is the above code? Since the
>(now)
>struct is well defined, doesn't contain the keyword 'virtual', there's
>no
>derivation involved then when dealing with any pointer-to-A, if you
>dereference
>said pointer to call the function f() then there's only one possible
>function
>to call.

When the function call is made, two arguments are forwarded to f(). One
of those is a pointer (the value in pA). If that pointer is invalid (is
outside the range of pointers -addresses- available to your program at
the time of execution of that statement) you have undefined behaviour.
Quite a few platforms may abort your process with a segment violation
fault.

To argue that the compiler will optimise away all the problems is just
asking for trouble. One day that f() will be changed with disastrous
consequences. I believe that writing unnecessarily flaky code is
unprofessional.

Guideline:

Do not write member functions that do not use any characteristic of the
class (one reason namespaces were invented was to make this completely
unnecessary)

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Steve Clamage

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
"Andrei Alexandrescu" <alexan...@micromodeling.com> writes:

>Hello, the problem is simple:

>class A {


> int f(int i) { return i + 5; }
>};

>int main()
>{
> A * pA;
> pA->f(1);
>}

>The question is, is the code guaranteed to work? Please refrain yourselves


>from making comments on bad style etc. I've seen this in a test.

Auto variale pA is not initialized, but must be dereferenced
to call the non-static member function f. The results of the program
are undefined by the standard, meaning anything at all might happen.

A helpful compiler will complain about using an uninitialized
variable, and is within its rights to refuse to compile the
program at all.

Some runtime systems cause uninitialized variables to have values
that result in a run-time trap if accessed before being set. On
such a system the program would abort at run time, if the compiler
accepted the code in the first place.

--
Steve Clamage, stephen...@sun.com

Francis Glassborow

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
In article <369c9f6c....@news.demon.co.uk>, John Goodwin
<J...@opticon.demon.co.uk> writes

>>Andrei Alexandrescu wrote:
>>>
>>> class A {
>>> int f(int i) { return i + 5; }
>>> };
>>> int main()
>>> {
>>> A * pA;
>>> pA->f(1);
>>> }
>>> The question is, is the code guaranteed to work?
>>
>>No. It is undefined behaviour since a member function on an invalid
>>(uninitialized) object is invoked. It is equivalent to (*pA).f(1), and,
>>there is no object at (*pA).
>
>It may be useful to consider it that way at a higher level, but most
>ordercode processors would not in fact operate in that fashion.
>The *call* to the member function above does not require a pointer.
>True the uninitialisd pA will be passed (without dereferencing), but
>since this is not used it's hard to see how it would cause an error.
>
>I'd be interested to see if anyone can suggest how it could be
>compiled to produce an error (assuming no debug code is introduced).

The type of f is pointer to member taking an int and returning an int.

Without optimisation:

the code must dereference f (that is the way functions work) to obtain

the location of f, the arguments for the call (this and a temp int with


value 1) placed for transfer. At this stage you have a wild pointer
floating around.

The very fact that even the simplest compiler circumvents this is what
makes writing code so very dangerous. Its working relies entirely on


several fortuitous circumstances (non-virtual function, makes no access
to member data etc.)

I do not believe that any programmer would actually write such code as a


permanent feature. It has a distinct feel of being a place holder.

Put it another way, the code may 'work' on most compilers but any team


leader that allowed code like that out of the door would have to work
very hard to remain in work:) in a respectable software shop.

Francis Glassborow Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA +44(0)1865 246490
All opinions are mine and do not represent those of any organisation

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Francis Glassborow

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
In article <369c9a19....@news.demon.co.uk>, John Goodwin
<J...@opticon.demon.co.uk> writes

>Can you elaborate why you beleive it *cannot* work.

Sorry, when I say cannot work, I mean reliably whatever is later added
to the implementation. In particular accessing any data member of A
will cause potentially catestrophic failure.

>
>[It works perfectly on VC4.2 (after making f public)]


>
>pA could contain *anything*, but since the "this" pointer is never
>used, implicitly or explicitly, why should it fail?

It is 'used' (technical term defined somewhere in the standard),


because it is passed as an argument to f().

Francis Glassborow Chair of Association of C & C++ Users

Rolf F. Katzenberger

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
On 12 Jan 1999 14:42:05 -0500, in article <369b7...@10.1.1.65> "Andrei
Alexandrescu" <alexan...@micromodeling.com> wrote:

> Hello, the problem is simple:
>

> class A {
> int f(int i) { return i + 5; }

f isn't public.

> };

A has no public constructor.

> int main()
> {
> A * pA;

pA isn't pointing to an A.

> pA->f(1);
> }
>
> The question is, is the code guaranteed to work?

It doesn't even compile before you make f() public.


Regards,
Rolf


--
______________________________________________________________________
Rolf F. Katzenberger | Software Developer | Trainer 1998-11-18
Home: http://www.geocities.com/SiliconValley/Park/9557
PGP : http://wwwkeys.pgp.net:11371/pks/lookup?op=get&search=0x3B39491F

Jean-Francois Brouillet

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
{ Please quote moderately! -vdv }
----------
>From: J...@opticon.demon.co.uk (John Goodwin)
>Newsgroups: comp.lang.c++.moderated
>Subject: Re: Functions that don't use this, called with uninitialized pointers
>Date: Wed, Jan 13, 1999, 18:02
>

> On 13 Jan 1999 08:11:32 -0500, Francis Glassborow

> <fra...@robinton.demon.co.uk> wrote:
>
>>In article <369b7...@10.1.1.65>, Andrei Alexandrescu
> <alexandrescua@mi

>>cromodeling.com> writes


>>>Hello, the problem is simple:
>>>
>>>class A {
>>> int f(int i) { return i + 5; }

>>>};


>>>
>>>int main()
>>>{
>>> A * pA;

>>> pA->f(1);
>>>}
>>>


>>>The question is, is the code guaranteed to work? Please refrain
> yourselves
>>>from making comments on bad style etc. I've seen this in a test.
>>

>>It is guaranteed not to work. f() is a private member of A.
>>

>>Now make it a public member and it still cannot work as f() is a member
>>function and requires a this value. You are now deep in undefined
>>territory.
>

> Can you elaborate why you beleive it *cannot* work.
>

> [It works perfectly on VC4.2 (after making f public)]
>
> pA could contain *anything*, but since the "this" pointer is never
> used, implicitly or explicitly, why should it fail?

Consider first a slight modification...

class aa {
// empty
} ;

class A : public aa {
// rest same as above
} ;

Does this change the nature of the question ?

Now consider a slight variation:

class aa {
public:
virtual int f(int i) ;

} ;

class A : public aa {
// rest same as above
} ;


Now, is the usual "but why should it fail" so obvious ?

--
jean-franco...@virgin.net

mar...@my-dejanews.com

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
In article <369c9f6c....@news.demon.co.uk>,
J...@opticon.demon.co.uk (John Goodwin) wrote:
> On 13 Jan 1999 08:41:54 -0500, Biju Thomas <biju...@ibm.net> wrote:

>
> >Andrei Alexandrescu wrote:
> >>
> >> class A {
> >> int f(int i) { return i + 5; }
> >> };
> >> int main()
> >> {
> >> A * pA;
> >> pA->f(1);
> >> }
> >> The question is, is the code guaranteed to work?
> >
> >No. It is undefined behaviour since a member function on an invalid
> >(uninitialized) object is invoked. It is equivalent to (*pA).f(1), and,
> >there is no object at (*pA).
>
> It may be useful to consider it that way at a higher level, but most
> ordercode processors would not in fact operate in that fashion.
>
> The *call* to the member function above does not require a pointer.
> True the uninitialisd pA will be passed (without dereferencing), but
> since this is not used it's hard to see how it would cause an error.
>
> I'd be interested to see if anyone can suggest how it could be
> compiled to produce an error (assuming no debug code is introduced).
>
I know of at least one compiler that will generate code that will fail.

The old microsoft 16 bit compiler had an option to pass the 'this' pointer in
registers. If you compiled in "far" mode, that meant loading the high bits of
the address into ES. On the x86, just *loading* an invalid value into a
segment register causes a runtime exception - it doesnt wait until you *use*
it. So the above code would (most likely) fail.

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]

Steve Clamage

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
J...@opticon.demon.co.uk (John Goodwin) writes:

>On 13 Jan 1999 08:41:54 -0500, Biju Thomas <biju...@ibm.net> wrote:

>>Andrei Alexandrescu wrote:
>>>
>>> class A {
>>> int f(int i) { return i + 5; }
>>> };
>>> int main()
>>> {
>>> A * pA;
>>> pA->f(1);
>>> }
>>> The question is, is the code guaranteed to work?
>>
>>No. It is undefined behaviour since a member function on an invalid
>>(uninitialized) object is invoked. It is equivalent to (*pA).f(1), and,
>>there is no object at (*pA).

>It may be useful to consider it that way at a higher level, but most
>ordercode processors would not in fact operate in that fashion.

>The *call* to the member function above does not require a pointer.
>True the uninitialisd pA will be passed (without dereferencing), but
>since this is not used it's hard to see how it would cause an error.

>I'd be interested to see if anyone can suggest how it could be
>compiled to produce an error (assuming no debug code is introduced).

On a tagged architecture, attempting to read a pointer value that
is not valid results in a runtime trap that will by default abort
the program. It is not necessary to dereference the pointer to get
a trap; attempting to read the value is enough.

A pointer-checking C++ runtime system could have the same behavior.

The original question was whether the code was guaranteed to
work. Any expression of the forms
p->data_member
p->func_member()
whether static or nonstatic data or function members, has undefined
behavior unless p points to an object of the appropriate type.

Even when accessing a static member, the standard requires that

the object-expression to the left of the "->" be evaluated, and


"a->b" is defined to mean the same thing as "(*a).b".

Undefined behavior means that there are no guarantees.

--
Steve Clamage, stephen...@sun.com

Alex Martelli

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
Larry Brasfield wrote in message
[snip]

>It's not a matter of style. A member function that does
>not do anything with the class instance upon which it
>must be called is plain stupid. It is likely to be inefficient
>and perplexing at the call site(s). Failing to declare it
>static is a way of confounding the purpose of the function
>that goes beyond mere style.


Personally, I rate it just about on a par with any
other function that does not use all of the parameters
that are passed to it (and C++ even includes an
extension to C to facilitate other cases of such
functions, i.e. unnamed parameters): i.e., pretty
normal in evolving code. Perhaps the function does
not use the parameter TODAY, but it used to, and
maybe will again -- meanwhile, one keeps the
parameter there; why make all clients recompile?!
Not a very strong issue, but a frequent one.

Or perhaps, and this is a perfectly reasonable case
that also applies to completely stable code!, there
is a pointer-to-member somewhere, that must be
able to point to this function, or alternatively to
others; it is then quite reasonable to supply this
function with extra arguments it will not use (and
this includes the "this" pointer!), to "extend", so
to speak, its signature to that of the other functions
it must be interchangeable with. This may not be
a very frequent case, but it IS a very strong
argument for asserting that "plain stupid" is a
very unwise judgment to make for this idiom.

None of this has anything to do with calling a
function through an uninitialized pointer, which
is and remains undefined behaviour, whether the
function "uses" the this pointer or not.


Alex

-----------== Posted via Newsfeeds.Com, Uncensored Usenet News ==----------
http://www.newsfeeds.com/ The Largest Usenet Servers in the World!
-----------== Over 66,000 Groups, Plus a Dedicated Binaries Server
==----------

Biju Thomas

unread,
Jan 15, 1999, 3:00:00 AM1/15/99
to
Rolf F. Katzenberger wrote:
>
> On 12 Jan 1999 14:42:05 -0500, in article <369b7...@10.1.1.65> "Andrei
> Alexandrescu" <alexan...@micromodeling.com> wrote:
>
> >
> > class A {
> > int f(int i) { return i + 5; }
> > };
>
> A has no public constructor.
>

That is not true. The default constructor (provided by the compiler) is
public. Otherwise, what is the use of default constructor?

--
Regards,
Biju Thomas

Andrew Koenig

unread,
Jan 15, 1999, 3:00:00 AM1/15/99