Topic: Does the past-the-end pointer refer to an object?
Author: litb <Schaub-Johannes@web.de>
Date: Sun, 14 Jun 2009 10:04:24 CST Raw View
On Jun 14, 3:22 pm, Mathias Gaunard <loufo...@gmail.com> wrote:
> On 14 juin, 11:29, litb <Schaub-Johan...@web.de> wrote:
>
> > > A valid value of an object pointer type represents either the address of a byte in memory (1.7) or a null pointer (4.10).
>
> > This seems to say that any (object-) pointer that is valid (contains a
> > valid value) refers to an object, and in particular, this seems to
> > imply that there is always (at least) a 1-byte object located at each
> > past-the-end location, and the following example is always well
> > formed.
>
> I can't see how you can deduce that. It just says a valid value for a
> pointer is either the address of a byte or null.
>
I'm not sure what "a byte in memory" means. I thought it means that
there is a byte that i can write/read to and from. So i thought the
following is always guaranteed to work:
unsigned char c[1];
int a = c[1];
But the following can be undefined behavior, since it's not guaranteed
that there is a suitable sized and represented object at that location
we try to read a float from.
float c[1];
float a = c[1];
But i think i was on a wrong way. Saying "byte in memory" doesn't seem
to imply that the byte actually represents a region of storage (which
would make it to an object?). So is the difference between "memory"
and "storage" that the former is *available* storage, and the latter
is *owned* storage (representing an object and having associated
properties)? I can't spot a definition of these two (memory and
storage) in the Standard.
Can someone clearify the matter further? Thanks for all helps
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Richard Corden <richard.corden@gmail.com>
Date: Mon, 15 Jun 2009 11:53:59 CST Raw View
Hi,
Francis Glassborow wrote:
litb wrote:
Hi all.
I'm currently thinking of dereferencing the past-the-end pointer. And
i think it's well defined now. I thought the opposite before, but
after reading 3.9.2[basic.compound]/3, i think i'm allowed to
dereference - as long as i don't do an lvalue-to-rvalue conversion:
[...]
No it is clearly flawed. Why? because what object would dereferencing
a past the end pointer be? Dereferencing means to obtain the object
that is being pointed to.
Writing a[3] IS dereferencing. Now I can see your thinking however
let us step back and ask ourselves how you would use par anywhere
subsequent to its declaration without invoking undefined behaviour?
Perhaps the declaration never has bad consequences in any code but so
what. Undefined behaviour is not required to do bad things. However
declaring an unusable name seems pretty stupid to me.
There may be a flaw in your argument in that it's not clear that it is
the dereference which causes the undefined behaviour.
Core issue 232 suggests that undefined behaviour only applies when an
'lvalue-to-rvalue' conversion takes place:
http://std.dkuug.dk/JTC1/SC22/WG21/docs/cwg_active.html#232
The paragraph has:
Notes from the October 2003 meeting:
See also issue 315, which deals with the call of a static member
function through a null pointer.
We agreed that the approach in the standard seems okay: p = 0; *p; is
not inherently an error. An lvalue-to-rvalue conversion would give it
undefined behaviour.
Applying this to the &a[5] example, (ie. &*(a+5)):
- 'operator *' returns an lvalue
- 'operator &' expects an lvalue
There is no lvalue-to-rvalue conversion, and so we don't have
undefined behaviour.
Regards,
Richard
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
--
Richard Corden
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: litb <Schaub-Johannes@web.de>
Date: Tue, 16 Jun 2009 00:16:42 CST Raw View
On 14 Jun., 18:04, litb <Schaub-Johan...@web.de> wrote:
> On Jun 14, 3:22 pm, Mathias Gaunard <loufo...@gmail.com> wrote:
>
> > On 14 juin, 11:29, litb <Schaub-Johan...@web.de> wrote:
>
> > > > A valid value of an object pointer type represents either the address of a byte in memory (1.7) or a null pointer (4.10).
>
> > > This seems to say that any (object-) pointer that is valid (contains a
> > > valid value) refers to an object, and in particular, this seems to
> > > imply that there is always (at least) a 1-byte object located at each
> > > past-the-end location, and the following example is always well
> > > formed.
>
> > I can't see how you can deduce that. It just says a valid value for a
> > pointer is either the address of a byte or null.
>
> I'm not sure what "a byte in memory" means. I thought it means that
> there is a byte that i can write/read to and from.
> [cut...]
> But i think i was on a wrong way. Saying "byte in memory" doesn't seem
> to imply that the byte actually represents a region of storage (which
> would make it to an object?). So is the difference between "memory"
> and "storage" that the former is *available* storage, and the latter
> is *owned* storage (representing an object and having associated
> properties)? I can't spot a definition of these two (memory and
> storage) in the Standard.
>
> Can someone clearify the matter further? Thanks for all helps
>
I think i know the difference now. "Storage" is just some kind of
address space in which things may be stored. And memory is a certain
kind of storage for objects in C++. The C rationale says
> Because the address of a register variable cannot be taken, objects of storage class register effectively exist in a space distinct from other objects. (Functions occupy yet a third address space). This makes them candidates for optimal placement, the usual reason for declaring registers, but it also makes them candidates for more aggressive optimization.
I think this has something to do with that? Although in C++ "register"
degraded to rather a hint than to say register objects occupy a
different kind of storage, i think the C++ term "storage" still kept
this meaning along. So in C++ there may be "memory" and "code" storage
(for functions), for example. And 1.8/1 says in a note "A function is
not an object, regardless of whether or not it occupies storage in the
way that objects do. " - i think that hints that functions may also
use memory storage.
Seen this way, i would say 3.9.2/3 just says that a valid value of a
object pointer contains the address of a byte in memory, while memory
is not necessarily always "valid". Several examples contain the phrase
"valid memory", which i think should point to the fact that there is
also "invalid memory", one that is/may be available, but not yet
allocated?
If these thinkings are true, dereferencing a past-the-end pointer
should be undefined behavior, because dereferencing would yield an
evaluated expression, but lvalue expressions must refer to either a
function or object, which would then not be guaranteed anymore, thus
yielding to UB by omission (what happens if lvalue doesn't refer to
object?). Core issue 232 says that they "agree" that there should be
no UB unless an lvalue->rvalue is happening. But that isn't reflected
in the Standard, it seems.
Thanks for any pointers again.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Nick Hounsome <nick.hounsome@googlemail.com>
Date: Mon, 22 Jun 2009 08:16:34 CST Raw View
> > I'm not sure what "a byte in memory" means. I thought it means that
> > there is a byte that i can write/read to and from.
> > [cut...]
> > But i think i was on a wrong way. Saying "byte in memory" doesn't seem
> > to imply that the byte actually represents a region of storage (which
> > would make it to an object?). So is the difference between "memory"
> > and "storage" that the former is *available* storage, and the latter
> > is *owned* storage (representing an object and having associated
> > properties)? I can't spot a definition of these two (memory and
> > storage) in the Standard.
I think that you'll find that the whole 'one-past-the-end' thing was
originally introduced to deal with segmented memory architectures or
worse.
In a segmented architecture - if the compiler butted your array right
up tight to the end of a segment then one-past-the end would be in a
completely different segment and you couldn't therfore compare a
pointer to it to any pointer actually in the array. ( A similar
example for non-segmented would be if the compiler put the array right
at the top of memory and I believe that the old MS/intel near pointers
effectively make the same effect possible withina segment)
On some architectures, even putting such a value into an address
register might segfault.
So on-past-the end is really a mechanism to ensure that the compiler
always leaves enough space after the end of an array such that raw
pointer comparisons and arithmetic do the right thing - This doesn't
require a whole object - just a single byte in principle.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: James Kuyper <jameskuyper@verizon.net>
Date: Mon, 22 Jun 2009 12:06:33 CST Raw View
Nick Hounsome wrote:
....
> I think that you'll find that the whole 'one-past-the-end' thing was
> originally introduced to deal with segmented memory architectures or
> worse.
The main motivation for allowing one-past-the-end pointers is not
anywhere near that obscure. They are allowed to support the very common
idiom:
int array[LENGTH];
int *pi;
for(pi = 0; pi < array+LENGTH; pi++)
/* Body of loop */;
This idiom pre-dates K&R C, never mind ANSI/ISO C, and is still in use
in C++ code, though in many places it's hidden inside a template.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: litb <Schaub-Johannes@web.de>
Date: Sun, 14 Jun 2009 03:29:23 CST Raw View
Hi all.
I'm currently thinking of dereferencing the past-the-end pointer. And
i think it's well defined now. I thought the opposite before, but
after reading 3.9.2[basic.compound]/3, i think i'm allowed to
dereference - as long as i don't do an lvalue-to-rvalue conversion:
> A valid value of an object pointer type represents either the address of a byte in memory (1.7) or a null pointer (4.10).
This seems to say that any (object-) pointer that is valid (contains a
valid value) refers to an object, and in particular, this seems to
imply that there is always (at least) a 1-byte object located at each
past-the-end location, and the following example is always well
formed.
int a[3];
int *pa = &a[0], *pae = &a[3];
int &par = a[3];
But reading a value/accessing the stored value isn't guaranteed to
work, because we don't know what type that object has and could
validate both 3.10/15 and 4.1/1.
Is my thinking about this correct? Thanks for any pointers.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Francis Glassborow <francis.glassborow@btinternet.com>
Date: Sun, 14 Jun 2009 07:20:58 CST Raw View
litb wrote:
>
> Hi all.
>
> I'm currently thinking of dereferencing the past-the-end pointer. And
> i think it's well defined now. I thought the opposite before, but
> after reading 3.9.2[basic.compound]/3, i think i'm allowed to
> dereference - as long as i don't do an lvalue-to-rvalue conversion:
>
>> A valid value of an object pointer type represents either the address of a byte in memory (1.7) or a null pointer (4.10).
>
> This seems to say that any (object-) pointer that is valid (contains a
> valid value) refers to an object, and in particular, this seems to
> imply that there is always (at least) a 1-byte object located at each
> past-the-end location, and the following example is always well
> formed.
>
> int a[3];
> int *pa = &a[0], *pae = &a[3];
> int &par = a[3];
>
> But reading a value/accessing the stored value isn't guaranteed to
> work, because we don't know what type that object has and could
> validate both 3.10/15 and 4.1/1.
>
> Is my thinking about this correct? Thanks for any pointers.
>
No it is clearly flawed. Why? because what object would dereferencing
a past the end pointer be? Dereferencing means to obtain the object
that is being pointed to.
Writing a[3] IS dereferencing. Now I can see your thinking however
let us step back and ask ourselves how you would use par anywhere
subsequent to its declaration without invoking undefined behaviour?
Perhaps the declaration never has bad consequences in any code but so
what. Undefined behaviour is not required to do bad things. However
declaring an unusable name seems pretty stupid to me.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]
Author: Mathias Gaunard <loufoque@gmail.com>
Date: Sun, 14 Jun 2009 07:22:38 CST Raw View
On 14 juin, 11:29, litb <Schaub-Johan...@web.de> wrote:
> > A valid value of an object pointer type represents either the address of a byte in memory (1.7) or a null pointer (4.10).
>
> This seems to say that any (object-) pointer that is valid (contains a
> valid value) refers to an object, and in particular, this seems to
> imply that there is always (at least) a 1-byte object located at each
> past-the-end location, and the following example is always well
> formed.
I can't see how you can deduce that. It just says a valid value for a
pointer is either the address of a byte or null.
--
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]