Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

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

44 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
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 15, 1999, 3:00:00 AM1/15/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

John Goodwin

unread,
Jan 15, 1999, 3:00:00 AM1/15/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]

John Goodwin

unread,
Jan 15, 1999, 3:00:00 AM1/15/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 15, 1999, 3:00:00 AM1/15/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 15, 1999, 3:00:00 AM1/15/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 15, 1999, 3:00:00 AM1/15/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 15, 1999, 3:00:00 AM1/15/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 15, 1999, 3:00:00 AM1/15/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.

Steve Clamage

unread,
Jan 16, 1999, 3:00:00 AM1/16/99
to
Francis Glassborow <fra...@robinton.demon.co.uk> writes:

>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?

The first edition (1986) does indeed describe static data
members (section 5.4.4), but static member functions appear
not to be part of the language at that time. (Section 8.5.1
says member function cannot be declared static, in particular.)

The ARM lists in section 18.1.2 static member functions as a
feature added after 1985.

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

John Goodwin

unread,
Jan 16, 1999, 3:00:00 AM1/16/99
to
On 15 Jan 1999 01:09:36 -0500, cla...@Eng.Sun.COM (Steve Clamage)
wrote:

>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.
>

So, to put it in a nut shell:

No, the standard does not require that a compliant compiler force its
target ordercode processor to perform a spurious evaluation.

That's all I wanted to confirmed.

JG

John Goodwin

unread,
Jan 16, 1999, 3:00:00 AM1/16/99
to
On 14 Jan 1999 12:03:48 -0500, Valentin Bonnard <bonn...@pratique.fr>
wrote:


>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.

I appreciate that, however different people use different definitions
and we don't all spend *all* our time discussing C++ exclusively. I
appreciated that I was discussing something in a C++ group, hence it
is a reasonable question.

Generaly, I would not consider placing a literal in the IP register,
or moving a value from one place to another with no indirection as
examples of dereferencing.

I was just asking if there was a definition in the standard (of which
I am not aware) that would allow one of these cases as an example of
dereferencing.

If there is not, then

"but must be dereferenced to call the non-static member function f"

Which is wrong in practice, is either wrong according to the standard,
or indicates an absurdity within the standard.

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

As usual, people are not reading the question properly. I certainly
was never arguing with the two lines quoted above.

Do you maintain that all ordercode processors will *actually* perform
a dereference operation ? (My posts were about whether there is any
*actual* dereferencing).

If so, you'll need to be using a very broad definition of dereference,
broader I would imagine than the one in the standard!

Francis Glassborow

unread,
Jan 16, 1999, 3:00:00 AM1/16/99
to
In article <F5KB1...@research.att.com>, Bjarne Stroustrup
<b...@research.att.com> writes
>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 :-).

Thanks. And I should have thought to check in D&E (its even in the
index:) and I note you credit Martin O'Riordan with the idea as well as
describing
((X*)0) -> f()
as a time bomb (and at least that method uses a null pointer rather than
an unitialised one.)


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 ]

Mungo Henning

unread,
Jan 16, 1999, 3:00:00 AM1/16/99
to
Francis Glassborow wrote:
>
>
[snip]

> 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.

Is this a specialism for the "this" pointer, or is it a general truism?

Whilst I must agree with the sentiment that handling 'bad' pointers
isn't conducive to good programming, I'm having a problem understanding
the harm in being given something which is not used (and is therefore
harmless).
If the problem is not particular to "this", what of the circumstance
where we have (say):
int g(int i, char*)
{
return i + 1;
}

and there's a call such as:
int k = g(42,(char*)1);

Whilst not advocating such coding, I'm imagining the circumstances of a
large project with many calls to g() and a subsequent change of g()'s
code so that the char* isn't used inside the function.

Also [just re-read Francis' words quoted above] is NULL outside the range of
addresses
available to the program? If so, then any supply of a NULL pointer will
also give 'undefined' behaviour.

Thanks in advance

Mungo Henning

Francis Glassborow

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

>>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" ?

Of course the 'as if' rule applies. But the point is that it would
never be wrong for the compiler to insert such code. We are talking
about what is guaranteed as distinct from what you expect.

>
>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.

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 ]

Siemel Naran

unread,
Jan 17, 1999, 3:00:00 AM1/17/99
to
On 15 Jan 1999 16:52:11 -0500, Steve Clamage <cla...@Eng.Sun.COM> 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);
>>}

>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.

What do you mean by "within its rights to refuse to compile the
program"? Isn't such a compiler non-conforming? Here's my
reasoning. The expression "A * pA" taken alone is valid. The
expression "pA->f(1)" take alone is valid. All of this means
that the program should compile.

A good compiler will give the warning "in line 2 of main(),
variable 'pA' is used before its value is set". But can a
conforming compiler actually refuse to compile the program?

If the compiler analyzes line1 and line2, it finds that the
program is faulty in that a crash is possible at runtime. In
other words, the expression "pA->f(1)" taken together with the
the other expressions is not valid. This seems like a context
dependent rule -- that is, the correctness of the expression
"pA->f(1)" depends on other expressions in the program.

To me, it seems reasonable for a compiler to refuse to compile
the above program, although such a compiler seems non-conforming
to me (perhaps 'super-conforming' is a better word). There are
other context dependent rules that a compiler can enforce. Eg,

int main() { const int i=3; int& ii=const_cast<int&>(i); ii=7; }

All the statements in the above program, taken alone, are valid
and hence the program should compile. But analyzing the second
expression, we see that we are trying to remove the const
qualifier on an object that is initially const. This const_cast
is deadly because the variable 'i' could be stored in read-only
memory. So is it within the rights of a compiler to refuse to
compile the above program?

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

Siemel Naran

unread,
Jan 17, 1999, 3:00:00 AM1/17/99
to
On 15 Jan 1999 17:45:21 -0500, Andrew Koenig <a...@research.att.com> wrote:
>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

Consider the following function
struct X { };
void f(X*) { }

Now consider this program
int main() { X * x=new X(); delete x; f(x); }
The function f(...) is called with a bogus pointer -- one that points
to memory that has been deallocated. So is it reasonable for a
program crash to occur? To me, the answer is YES. This might happen
if the variable 'x' is placed in one of those pointer registers you
mentioned, and a program crash results because the process/thread no
longer owns the memory pointed to by 'x'.

But consider this program
int main() { X * x=0; f(0); }
Since the process/thread does not own the null pointer, is it
reasonable for a program crash to occur? The answer is NO because
it is reasonable to call a function with a null pointer.

Now consider the following class
struct X { void f() { } };
whose C style representation of the function is
void f(X*) { }

Now consider this program
int main() { X * x=0; f(x); }
>From what you've said in the quoted text, a program crash is possible
because the process/thread does not own the memory pointed to by the
null pointer. OTOH, as it is reasonable to call a function with a
null pointer, a crash should not immediately occur.


So my question is whether the pointer "this" is different from a
pointer of type "X*"? That is, is it true that an implementation
cannot put an ordinary pointer of type "X*" into one of those special
address registers, but it can put the pointer "this" into one of
those special address registers?

This idea seems in keeping with the idea that the type of "this" is
"X&". It is conceivable that "this" would have had the type "X&"
rather than "X *const" if references were invented because the
concept of classes.

Steve Clamage

unread,
Jan 18, 1999, 3:00:00 AM1/18/99
to
sbn...@localhost.localdomain (Siemel Naran) writes:

>On 15 Jan 1999 16:52:11 -0500, Steve Clamage <cla...@Eng.Sun.COM> 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);
>>>}

>>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.

>What do you mean by "within its rights to refuse to compile the
>program"?

The behavior of pA->f(1) is undefined, as I have explained
in detail in other messages in this thread.

"Undefined behavior" means literally that the standard places no
requirements whatever on the implementation. Whatever the compiler
(or runtime system) does is acceptable according the the standard.
That's what I meant by "within its rights".

>Isn't such a compiler non-conforming? Here's my
>reasoning. The expression "A * pA" taken alone is valid. The
>expression "pA->f(1)" take alone is valid. All of this means
>that the program should compile.

Not at all. The expression pA->f(1) is valid only if certain
requirements are met. Among them is the requirement that
pA point to an object of appropriate type, which it does not.

>A good compiler will give the warning "in line 2 of main(),
>variable 'pA' is used before its value is set". But can a
>conforming compiler actually refuse to compile the program?

Yes, because the program's behavior is undefined. Refer to 1.3.12
in the C++ standard.

>If the compiler analyzes line1 and line2, it finds that the
>program is faulty in that a crash is possible at runtime. In
>other words, the expression "pA->f(1)" taken together with the
>the other expressions is not valid. This seems like a context
>dependent rule -- that is, the correctness of the expression
>"pA->f(1)" depends on other expressions in the program.

Of course! Consider this program:
#include <string.h>
int main() {
const char* p;
char q[10];
strcpy(q, p);
}
As written, the program has undefined behavior, because the
value of p is undefined. Change the first statement of main to
const char* p = "Hello";
and the behavior of the program is completely defined.
Change the first statement of main to
const char* p = "Hello, world!";
and the program's behavior is undefined again, since strcpy will
try to write beyond the end of q.

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

Francis Glassborow

unread,
Jan 18, 1999, 3:00:00 AM1/18/99
to
In article <slrn7a1dsq....@localhost.localdomain>, Siemel Naran
<sbn...@localhost.localdomain> writes

>What do you mean by "within its rights to refuse to compile the
>program"? Isn't such a compiler non-conforming? Here's my

>reasoning. The expression "A * pA" taken alone is valid. The
>expression "pA->f(1)" take alone is valid. All of this means
>that the program should compile.

One of the options that a compiler always has is to diagnose that
undefined behaviour WILL happen if this code is executed. Having made
that diagnosis it knows that the program is not well-formed and can then
do anything it likes with it.


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 18, 1999, 3:00:00 AM1/18/99
to
Mungo Henning <mun...@itacs.strath.ac.uk> writes:

>Francis Glassborow wrote:
>>
>> 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.

>Is this a specialism for the "this" pointer, or is it a general truism?

> ...


>Also [just re-read Francis' words quoted above] is NULL outside the range of
>addresses
>available to the program? If so, then any supply of a NULL pointer will
>also give 'undefined' behaviour.

The results of attempting to read the value of an unintialized
variable (which is what started this thread) are undefined. The
standard allows, for example, a hardware architecture or runtime
system that can detect an attempt to read an uninitialized variable.
Such systems exist.

As to pointers, the standard specifies what happens when you use
a pointer value that refers to a valid object, or one which is
null. Attempting to use other pointer values has undefined results.
Again, the standard allows an implementation to validate any
attempted use of a pointer value. Some hardware architectures trap
any attempt to assign an invalid value to a pointer. (The NULL
value is always valid for assignment or reading, by language
definition; it is not valid for dereferencing.)

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

Francis Glassborow

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

>Also [just re-read Francis' words quoted above] is NULL outside the range of
>addresses
>available to the program? If so, then any supply of a NULL pointer will
>also give 'undefined' behaviour.

In this context NULL is actually less dangerous because it is guaranteed
that you can load a null pointer const into an address register. That
is not true for any 'bad' pointer.


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 ]

John Goodwin

unread,
Jan 18, 1999, 3:00:00 AM1/18/99
to
On 16 Jan 1999 20:56:16 -0500, Francis Glassborow
<fra...@robinton.demon.co.uk> wrote:

>In article <369de263....@news.demon.co.uk>, John Goodwin
><J...@opticon.demon.co.uk> writes
>>>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.
>>>

[1]

>>>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" ?
>
>Of course the 'as if' rule applies. But the point is that it would
>never be wrong for the compiler to insert such code. We are talking
>about what is guaranteed as distinct from what you expect.

Of course. I don't think that *anyone* has posted to say otherwise.

Several people, on the other hand have made posts that seemed to imply
that a standard compliant compiler *must* insert such code (as per the
sentence marked [1] ).

Some people have gone into great depth on the subject, but at the end
of the day, the simple answer is, that a compiler can be standard
compliant, and produce working code (which is probably less desireable
than having it flag an error, or produce code that is gauranteed to
fail, but such is life).

Nobody has said such code is gauranteed to work, or that it is a good
idea :)

JG

James...@dresdner-bank.com

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

J...@opticon.demon.co.uk (John Goodwin) wrote:
> On 14 Jan 1999 12:03:48 -0500, Valentin Bonnard <bonn...@pratique.fr>
> wrote:
>
> >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.
>
> I appreciate that, however different people use different definitions
> and we don't all spend *all* our time discussing C++ exclusively. I
> appreciated that I was discussing something in a C++ group, hence it
> is a reasonable question.
>
> Generaly, I would not consider placing a literal in the IP register,
> or moving a value from one place to another with no indirection as
> examples of dereferencing.

The standard uses a very simple and very precise definition of
dereferencing. If a pointer is the operand of a unary * operator, or
the first operand of a ->, and the expression is potentially evaluated,
the pointer is dereferenced. The standard can hardly say anything else,
since it cannot specify exactly what code must be generated, and the
immediate effects of "dereferencing" are not "observable behavior",
which is all that the standard does specify.

> I was just asking if there was a definition in the standard (of which
> I am not aware) that would allow one of these cases as an example of
> dereferencing.
>
> If there is not, then
>
> "but must be dereferenced to call the non-static member function f"
>
> Which is wrong in practice, is either wrong according to the standard,
> or indicates an absurdity within the standard.

There is no must or must not. The pointer is dereferenced. By
definition.

> >pointer->member means (*pointer).member. Isn't * usally called the
> >dereferencement operator ?
>
> As usual, people are not reading the question properly. I certainly
> was never arguing with the two lines quoted above.

But that's what you are doing.

> Do you maintain that all ordercode processors will *actually* perform
> a dereference operation ? (My posts were about whether there is any
> *actual* dereferencing).

No. In practice, *any* use of an uninitialized variable (pointer or
not) is undefined behavior. So the standard doesn't require anything of
the implementation. What it does require is that *if* the variable were
correctly initialized, the observable behavior of the program be the
same as if the variable had been physically read.

> If so, you'll need to be using a very broad definition of dereference,
> broader I would imagine than the one in the standard!

The definition in the standard is *very* narrow. If the pointer is the
operand of a unary *, or the first operand of a ->, and the expression
is evaluated (or potentially evaluated), the pointer is dereferenced.

--
James Kanze GABI Software,
Sàrl
Conseils en informatique orienté objet --
-- Beratung in industrieller
Datenverarbeitung
mailto: ka...@gabi-soft.fr mailto:
James...@dresdner-bank.com

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

James...@dresdner-bank.com

unread,
Jan 18, 1999, 3:00:00 AM1/18/99
to
In article <369F4FF0...@itacs.strath.ac.uk>,
Mungo Henning <mun...@itacs.strath.ac.uk> wrote:
> Francis Glassborow wrote:
> >
> >
> [snip]

>
> > 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.
>
> Is this a specialism for the "this" pointer, or is it a general truism?

In general. There are in fact three categories of pointers: invalid,
valid but not dereferenciable, and dereferenciable.

To be valid, a pointer must meet one of the following conditions: it
points to a valid object, it points to one past the end of an array, or
it is a null pointer. Only the first of these is dereferenciable.

Accessing an invalid pointer, or dereferencing a pointer which does not
point to a valid object, is undefined behavior.

James...@dresdner-bank.com

unread,
Jan 18, 1999, 3:00:00 AM1/18/99
to
In article <77u8k4$b17$1...@engnews1.eng.sun.com>,

cla...@Eng.Sun.COM (Steve Clamage) wrote:
> sbn...@localhost.localdomain (Siemel Naran) writes:
>
> >On 15 Jan 1999 16:52:11 -0500, Steve Clamage <cla...@Eng.Sun.COM> 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);
> >>>}
>
> >>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.

>
> >What do you mean by "within its rights to refuse to compile the
> >program"?
>
> The behavior of pA->f(1) is undefined, as I have explained
> in detail in other messages in this thread.
>
> "Undefined behavior" means literally that the standard places no
> requirements whatever on the implementation. Whatever the compiler
> (or runtime system) does is acceptable according the the standard.
> That's what I meant by "within its rights".

Is this also true if the two statements are in a function other than
main. As I understand it, the undefined behavior only occurs on
execution, and the compiler can only refuse to compile it if it can
prove that the code will actually be executed. This is obviously the
case here, in main, but if the code were in another function, wouldn't
the compiler have to prove that the function would actually be called
during the execution of the code, for all possible data sets.
(Difficult in the face of separate compile.)

James...@dresdner-bank.com

unread,
Jan 18, 1999, 3:00:00 AM1/18/99
to
In article <4Kk7O+A1...@robinton.demon.co.uk>,

Francis Glassborow <fran...@robinton.demon.co.uk> wrote:
> In article <slrn7a1dsq....@localhost.localdomain>, Siemel Naran
> <sbn...@localhost.localdomain> writes
> >What do you mean by "within its rights to refuse to compile the
> >program"? Isn't such a compiler non-conforming? Here's my
> >reasoning. The expression "A * pA" taken alone is valid. The
> >expression "pA->f(1)" take alone is valid. All of this means
> >that the program should compile.
>
> One of the options that a compiler always has is to diagnose that
> undefined behaviour WILL happen if this code is executed. Having made
> that diagnosis it knows that the program is not well-formed and can then
> do anything it likes with it.

Only if it can prove that the function will be executed, for all
possible data sets.

--

James...@dresdner-bank.com

unread,
Jan 18, 1999, 3:00:00 AM1/18/99
to
In article <77rc9r$3kh$1...@engnews1.eng.sun.com>,

cla...@Eng.Sun.COM (Steve Clamage) wrote:
> Mungo Henning <mun...@itacs.strath.ac.uk> writes:
>
> >Francis Glassborow wrote:
> >>
> >> 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.
>
> >Is this a specialism for the "this" pointer, or is it a general truism?
> > ...

> >Also [just re-read Francis' words quoted above] is NULL outside the range of
> >addresses
> >available to the program? If so, then any supply of a NULL pointer will
> >also give 'undefined' behaviour.
>
> The results of attempting to read the value of an unintialized
> variable (which is what started this thread) are undefined. The
> standard allows, for example, a hardware architecture or runtime
> system that can detect an attempt to read an uninitialized variable.
> Such systems exist.
>
> As to pointers, the standard specifies what happens when you use
> a pointer value that refers to a valid object, or one which is
> null. Attempting to use other pointer values has undefined results.

You forgot one past the end of an array.

John Goodwin

unread,
Jan 19, 1999, 3:00:00 AM1/19/99
to
On 18 Jan 1999 14:12:06 -0500, James...@dresdner-bank.com wrote:

snip

>> Generaly, I would not consider placing a literal in the IP register,
>> or moving a value from one place to another with no indirection as
>> examples of dereferencing.
>
>The standard uses a very simple and very precise definition of
>dereferencing. If a pointer is the operand of a unary * operator, or
>the first operand of a ->, and the expression is potentially evaluated,
>the pointer is dereferenced.

Very Orwellian :).

I can appreciate that, but what the standard says, and what the
ordercode processor does can be quite different. I was talking about
what happens on execution, not the rather specialised, and necessarily
pedantic wording of the standard.

>The standard can hardly say anything else,
>since it cannot specify exactly what code must be generated, and the
>immediate effects of "dereferencing" are not "observable behavior",
>which is all that the standard does specify.
>
>> I was just asking if there was a definition in the standard (of which
>> I am not aware) that would allow one of these cases as an example of
>> dereferencing.
>>
>> If there is not, then
>>
>> "but must be dereferenced to call the non-static member function f"
>>
>> Which is wrong in practice, is either wrong according to the standard,
>> or indicates an absurdity within the standard.
>
>There is no must or must not. The pointer is dereferenced. By
>definition.

By definition, maybe, by the relevant computer, perhaps not.

>> >pointer->member means (*pointer).member. Isn't * usally called the
>> >dereferencement operator ?
>>
>> As usual, people are not reading the question properly. I certainly
>> was never arguing with the two lines quoted above.
>
>But that's what you are doing.

No, I was trying to determine what the standard mandated in a
complaint compiler.

I've now got the answer to that question.

>> Do you maintain that all ordercode processors will *actually* perform
>> a dereference operation ? (My posts were about whether there is any
>> *actual* dereferencing).
>
>No. In practice, *any* use of an uninitialized variable (pointer or
>not) is undefined behavior. So the standard doesn't require anything of
>the implementation. What it does require is that *if* the variable were
>correctly initialized, the observable behavior of the program be the
>same as if the variable had been physically read.

We've already been through this some days back. Nobody has, to my
recollection disagreed with what you have stated above.

>> If so, you'll need to be using a very broad definition of dereference,
>> broader I would imagine than the one in the standard!
>
>The definition in the standard is *very* narrow. If the pointer is the
>operand of a unary *, or the first operand of a ->, and the expression
>is evaluated (or potentially evaluated), the pointer is dereferenced.

Actually, I'd say that is very broad :). And as I've said before, the
standard does not run code, computers do.

This thread has largely been about the nuances of the process of
applying the standard to the generation of code.

Essentially we've just said, that it's not guaranteed to work, and
it's not guaranteed to fail: it's undefined, which was where we
started :)

JG

Stanley Friesen [Contractor]

unread,
Jan 20, 1999, 3:00:00 AM1/20/99
to
In article <77ohri$d...@netlab.cs.rpi.edu>,

John Goodwin <J...@opticon.demon.co.uk> wrote:
>
>Can you explain *exactly* what you mean by "evaluated" ?

It means execute the code for any implied side effects.


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

Only if there is a way that a conforming program can tell the difference.
[This is the "as if" rule].

That is, the program must *act* as if the code were evaluated (aka
executed/dereferenced etc.).

Biju Thomas

unread,
Jan 22, 1999, 3:00:00 AM1/22/99
to
Stanley Friesen [Contractor] wrote:
>
> In article <77ohri$d...@netlab.cs.rpi.edu>,
> John Goodwin <J...@opticon.demon.co.uk> wrote:
> >
> >Can you explain *exactly* what you mean by "evaluated" ?
>
> It means execute the code for any implied side effects.

I have seen this "as if" rule in the standard. What are these
side-effects or observable behaviour that it is talking about?

Input/Output? Should be.

Memory Access? Probably.

Heat generated by the processor? Well, according to Quantum Mechanics,
no heat is generated unless somebody is there to measure it. A
reasonable compiler vendor can assume that programmers don't use
computers for heating their offices. So, it should not count.

Does the time spent for execution count as a side effect? According to
the "as if" rule, which of the following loops can be discarded by the
compiler?

int main ()
{
for ( int j = 0; j < 1000000000000; ++j ); // #1
for ( int j = 0; j < 1000; ++j ); // #2
for ( int j = 0; j < 1; ++j ); // #3
}

--
Regards,
Biju Thomas

Larry Brasfield

unread,
Jan 22, 1999, 3:00:00 AM1/22/99
to
Alex Martelli wrote in message <369d...@news2.newsfeeds.com>...
>Larry Brasfield wrote in message
(after an example of a member function that
never dereferences its 'this' pointer)
>>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.

There is a big difference between having a parameter
that may or may not be used and confusion as to the
need for a 'this' pointer. Even as an interface evolves,
I expect its designer, if there is one, to not require
clients to find some irrelevant class instance upon
which to call a non-static member function whose
semantics are those of a static member function. I
cannot regard such sloppiness in interface design
to be akin to uncertainty about the need for other
parameters in general. However, parameters that
do not participate in the stated semantics for a
function are just as bad. The static/non-static case
differs from other "mystery parameter" cases mainly
in how obviously it is bogus.

>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.

If I were to see that "stable code" requiring
arbitrary class instances to be found, (or useless
ones created), to enable calling a psuedo-static
member function, I think "reasonable" would
probably not be the applicable adjective.

However, I can imagine rare situations where
one might define a set of member functions,
all _nominally_ documented as operating upon
class instances, which would be composed in
some way (such as member function pointers)
instead of used individually. It could make
sense to have a non-static member function
that did not use its 'this' pointer.

I will retract "plain stupid" and replace it with
"rarely well thought out". I call things "stupid"
when they make no sense once carefully
examined. I have to admit that the problems
with confusion between functions on objects
and class functions are not "plain", at least
not to enough people to warrant my phrase.

In the case to which I was responding, the
creation of a bogus 'this' (using a dereference
of NULL, as I recall) was clearly not among the
set of cases where 'this' might or might not be
used in a reasonable design scenario. Such
cases necessarily involve passing valid class
instances to the member function.

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

.

Francis Glassborow

unread,
Jan 23, 1999, 3:00:00 AM1/23/99
to
In article <36A7E688...@ibm.net>, Biju Thomas <biju...@ibm.net>
writes

>I have seen this "as if" rule in the standard. What are these
>side-effects or observable behaviour that it is talking about?

If it is possible from within the program to determine that something
was or was not done you have an observable side-effect. If you can only
tell from some external measurement then that does not count. Basically
all observable side-effects can be made visible by an output message.
If it is not possible to change the output depending on whether an
action was actually exceuted then the code is within the bounds of the
'as if' rule.

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 23, 1999, 3:00:00 AM1/23/99
to
Biju Thomas <biju...@ibm.net> writes:

>I have seen this "as if" rule in the standard. What are these
>side-effects or observable behaviour that it is talking about?

The term is completely defined in the standard in section 1.9,
"Program execution". Here is a brief summary:

The standard defines an abstract machine and its behavior. It says,
"The observable behavior of the abstract machine is its sequence of
reads and writes to volatile data and calls to library I/O functions."
An implementation is only required to emulate the observable behavior
of the abstract machine. That requirement is referred to as the
"as-if" rule.

A somewhat silly example: Compilers have been known to incorporate
"benchmark recognizers" -- compile-time analysis that can detect
when a standard benchmark program is being compiled. The compiler
then generates code to emit the answer, without performing any
of the calcuations. Such a compiler conforms to the standard, in
that the observable behavior of the program matches the abstract
machine. It of course does not conform to the wishes of the
people who wrote or used the benchmark program. :-)

There are measures to cope with a benchmark-recognizing compiler,
once you have identified one by its unreasonably good performance.
The area of writing benchmarks and what compiler writers do in
response is a moderately entertaining subject in itself.

Biju Thomas

unread,
Jan 23, 1999, 3:00:00 AM1/23/99
to
Francis Glassborow wrote:
>
> In article <36A7E688...@ibm.net>, Biju Thomas <biju...@ibm.net>

> writes
> >I have seen this "as if" rule in the standard. What are these
> >side-effects or observable behaviour that it is talking about?
>
> If it is possible from within the program to determine that something
> was or was not done you have an observable side-effect. If you can only
> tell from some external measurement then that does not count. Basically
> all observable side-effects can be made visible by an output message.
> If it is not possible to change the output depending on whether an
> action was actually exceuted then the code is within the bounds of the
> 'as if' rule.

But, the time taken to execute the code is always a measureable,
observable side-effect. Then, how can any implementation
remove/substitute any code based on the 'as if' rule?

Or, does the C++ standard give a definition of observable side-effects
that the implementations have to take care of?

--
Regards,
Biju Thomas

David Kastrup

unread,
Jan 24, 1999, 3:00:00 AM1/24/99
to
Biju Thomas <biju...@ibm.net> writes:

> But, the time taken to execute the code is always a measureable,
> observable side-effect. Then, how can any implementation
> remove/substitute any code based on the 'as if' rule?
>
> Or, does the C++ standard give a definition of observable side-effects
> that the implementations have to take care of?

Of course it does. *Everything* it defines are the guaranteed
observable side-effects. Things like running times are not defined by
the C++ standard, so they can be anything.

--
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

Francis Glassborow

unread,
Jan 24, 1999, 3:00:00 AM1/24/99
to
In article <36AA3BCD...@ibm.net>, Biju Thomas <biju...@ibm.net>

writes
>But, the time taken to execute the code is always a measureable,
>observable side-effect. Then, how can any implementation
>remove/substitute any code based on the 'as if' rule?

But it is not measurable from within the program because there is no way
that a program knows how long it 'should take'. An observanle side-
effect is one that can always be detected from within a program (not
necessarily the program wriiten, but code could be added to do the
detection)

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 ]

Anthony Berent

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

Larry Brasfield wrote:

> However, I can imagine rare situations where
> one might define a set of member functions,
> all _nominally_ documented as operating upon
> class instances, which would be composed in
> some way (such as member function pointers)
> instead of used individually. It could make
> sense to have a non-static member function
> that did not use its 'this' pointer.
>

For a class designed and used in isolation I agree that it would be
slighly unusual to have a non-static member function that does not use
the this pointer. This however often changes if the class is part of an
inheritance structure or is to be used as a template parameter.

For example, the following code seems reasonable to me:

class Shape {
public:
virtual bool has_corners() = 0;
};
class Circle: public Shape {
bool has_corners() {return false;}
};
class Square: public Shape {
bool has_corners() {return true;}
};

A similar example could be built using templates.

My point is that a function being static or otherwise is, and should be,
a specification issue; whereas the use of the this pointer is an
implementation issue, and is only losely related to the specification
question.

- Anthony

James...@dresdner-bank.com

unread,
Jan 27, 1999, 3:00:00 AM1/27/99
to
In article <m2679xu...@mailhost.neuroinformatik.ruhr-uni-bochum.de>,

David Kastrup <d...@fsnif.neuroinformatik.ruhr-uni-bochum.de> wrote:
> Biju Thomas <biju...@ibm.net> writes:
>
> > But, the time taken to execute the code is always a measureable,
> > observable side-effect. Then, how can any implementation
> > remove/substitute any code based on the 'as if' rule?
> >
> > Or, does the C++ standard give a definition of observable side-effects
> > that the implementations have to take care of?
>
> Of course it does. *Everything* it defines are the guaranteed
> observable side-effects. Things like running times are not defined by
> the C++ standard, so they can be anything.

It's less restrictive than that. About all that counts as an observable
side effect are calls to the system (through the standard library) and
accessing volatile variables.

--
James Kanze GABI Software, Sàrl
Conseils en informatique orienté objet --
-- Beratung in industrieller Datenverarbeitung
mailto: ka...@gabi-soft.fr mailto: James...@dresdner-bank.com

-----------== 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 ]

0 new messages