Topic: How to avoid null references ?
Author: dave@boost-consulting.com (David Abrahams)
Date: Wed, 23 Mar 2005 19:46:25 GMT Raw View
nagle@animats.com (John Nagle) writes:
> Marc Schoolderman wrote:
>>> The 'strong conceptual similarity' I was referring to comes from the
>>> similar syntax and semantics used when dereferencing pointers and
>>> iterators. So, 'can't decrement a forward iterator' is not
>>> significant barrier to that similarity, but having one of them
>>> support dereferencing past-the-end values and the other not, would
>>> be a barrier.
>
> Actually, iterators have considerably more restrictive
> semantics than pointers. Which is good. For example,
>
> vector<int> tab;
> vector<int>::iterator p = tab.end();
> p++; // ILLEGAL
>
> Pointers are allowed to take on arbitrary values,
> as long as they're not dereferenced.
> Iterators are not.
??
int tab[10];
int* p = tab + 10;
p++; // ILLEGAL
It's been a while since I've looked, but that was ILLEGAL IIRC.
> And for iterators, some legal values are not dereferenceable.
int* q = tab + 10;
*q; // ILLEGAL
> There are implementations that check iterators, so those
> rules have teeth.
An implementation *could* check pointers the same way ;-)
Theoretically, of course.
--
Dave Abrahams
Boost Consulting
www.boost-consulting.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: Wed, 23 Mar 2005 22:35:06 CST Raw View
John Nagle wrote:
> Marc Schoolderman wrote:
> >> The 'strong conceptual similarity' I was referring to comes from
the
> >> similar syntax and semantics used when dereferencing pointers
and
> >> iterators. So, 'can't decrement a forward iterator' is not
> >> significant barrier to that similarity, but having one of them
> >> support dereferencing past-the-end values and the other not,
would
> >> be a barrier.
>
> Actually, iterators have considerably more restrictive
> semantics than pointers. Which is good. For example,
>
> vector<int> tab;
> vector<int>::iterator p = tab.end();
> p++; // ILLEGAL
>
> Pointers are allowed to take on arbitrary values,
???
How precisely is that different from:
int tab[10];
int *p = tab+10;
p++; // behavior undefined (5.7p5, last sentence)
> as long as they're not dereferenced. Iterators are not.
> And for iterators, some legal values are not dereferenceable.
Both (int*)0 and tab+10 are legal pointer values; neither of them is
dereferenceable.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: squell@alumina.nl (Marc Schoolderman)
Date: Sun, 6 Mar 2005 07:13:59 GMT Raw View
Thorsten Ottosen wrote:
> Add the indicated words to 5.3.1 expr.unary.op paragraph 1:
> The unary * operator performs indirection: the expression to which it is
> applied shall be a pointer to an object type, or a pointer to a function type
> and the result is an lvalue referring to the object or function to which the
> expression points, if any.
Because of the "if any", is this line of code still allowed?
int a[3]; int* end = &a[3]; // instead of a+3
Under the present wording, I believe this is valid because *(a+3) does
produce an lvalue - it would be undefined to convert it into an rvalue,
but this doesn't happen because of the & operator, so it's ok.
After these modifications, "a[3]" is an empty lvalue. What exactly does
it mean to take the address of an empty lvalue? The address-of operator
only says "The result of the unary & operator is a pointer to its operand.".
For obvious reasons, all 'empty lvalues' will 'retain' their address,
but I'm fuzzy how these changes state this.
~Marc
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: squell@alumina.nl (Marc Schoolderman)
Date: Mon, 7 Mar 2005 16:49:04 GMT Raw View
Thorsten Ottosen wrote:
> | Could you please provide real-world examples what an empty lvalue etc. is,
> | and how it is intended to be used?
> int* p = 0;
> int& r = *p;
Uh, check issue 453 - it explicitly forbids this.
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#453
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nospam@nospam.ucar.edu ("Thomas Mang")
Date: Thu, 10 Mar 2005 03:10:46 GMT Raw View
""Thorsten Ottosen"" <nesotto@cs.auc.dk> schrieb im Newsbeitrag
news:42234bc9$0$29273$14726298@news.sunsite.dk...
> ""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
> news:4220f20a$0$12126$3b214f66@usenet.univie.ac.at...
> |
> | ""Thorsten Ottosen"" <nesotto@cs.auc.dk> schrieb im Newsbeitrag
>
> | > the standard is going to change on this matter; the lates from the
October
> | > meeting says that
>
> | I don't get this. First, I was shocked when I read that modifications.
Now I
> | have the hope I am simply misunderstanding what it means.
> |
> | Could you please provide real-world examples what an empty lvalue etc.
is,
> | and how it is intended to be used?
>
> int* p = 0;
> ..
> int& r = *p;
> ..
> if( &r != 0 )
> {
> r = 5;
> }
Sorry for answering late.
What on earth is the usefullness of null-references?
Until now, references were great. It means you had an object. Say you write
a function that takes a reference - pretty common. The ones who called the
function knew they had to provide an object, the ones who wrote the function
implementation knew they got an object. If the object is not obligatory, you
simply provide an overload for that function. Simple, clear, straightforward
for the user and the implementor.
Now it seems null-references break this. It breaks the contract for
functions (everyone wants to pass in a null-reference now too and expect
defined behavior), it breaks the implementation that counts on a "non-null
reference".
What am I supposed to do? The quick and dirty solution is to document
somewhere whereever a reference is used, a valid object has to be provided.
The clean solution is to document for each and every parameter it must not
be a null reference, and of course inside the implementation an assert is
done it is indeed not a null-reference. That seems to be quite a lot of
work.
So what I am interested in is: What do the people wanting to get this into
C++0x gain? I see a lot to lose, I see lots of time wasted to modify existin
g code base to make it "compatible"/error resistant to this strange new
thing, but nothing to gain. Thus I don't like the idea at all (to put it
politely).
What are null-references supposed to do other than being a plague?
Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: falk.tannhauser@crf.canon.fr (=?ISO-8859-1?Q?Falk_Tannh=E4user?=)
Date: Thu, 10 Mar 2005 23:24:54 GMT Raw View
Thomas Mang wrote:
> What on earth is the usefullness of null-references?
I fully agree with your objections.
I followed the link posted in this thread by Marc Schoolderman on March 7
<http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#453> and in
my understanding, while the concept of "empty lvalues" is introduced to
clarify some consistency issues in the Standard, it will FORTUNATELY remain
illegal to bind such empty lvalues (in particular, dereferenced NULL pointers)
to references. So we can continue to sleep well...
However, binding references to not-yet-initialised objects is and remains
allowed, provided one doesn't do too much things which such a reference until
the initialisation completed.
Falk
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nesotto@cs.auc.dk ("Thorsten Ottosen")
Date: Thu, 10 Mar 2005 23:54:59 GMT Raw View
""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
news:422e00a6$0$11094$3b214f66@usenet.univie.ac.at...
| Sorry for answering late.
|
| What on earth is the usefullness of null-references?
well, you can say something like
vector<int> foo;
.
int* end = &*end();
instead of
int* end = &*begin() + foo.size();
I think, but I don't know for sure, that the motivation
was to make this and similar cases well-defined. With a new for loop, you
might want to say
for( int& f : foo | indirect )
if( &f )
f += 2;
instead of
for( int* f : foo )
if( f )
*f += 2;
Anyway, I think the general rule that says I can rely on a
reference argument to be valid is good; the caller should
check that the pointer is valid before dereferencing.
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ben-public-nospam@decadentplace.org.uk (Ben Hutchings)
Date: Fri, 11 Mar 2005 13:23:46 GMT Raw View
"Thorsten Ottosen" wrote:
> ""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
> news:422e00a6$0$11094$3b214f66@usenet.univie.ac.at...
>
>| Sorry for answering late.
>|
>| What on earth is the usefullness of null-references?
>
> well, you can say something like
>
> vector<int> foo;
> .
> int* end = &*end();
*end() remains undefined even if null/empty references can exist.
> instead of
>
> int* end = &*begin() + foo.size();
<snip>
Note that *begin() is also undefined if the size is 0, which is very
annoying when working with APIs that want array pointers.
--
Ben Hutchings
Unix is many things to many people,
but it's never been everything to anybody.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nesotto@cs.auc.dk ("Thorsten Ottosen")
Date: Fri, 11 Mar 2005 19:41:01 GMT Raw View
"Ben Hutchings" <ben-public-nospam@decadentplace.org.uk> wrote in message
news:slrnd32tap.3k7.ben-public-nospam@decadentplace.org.uk...
| "Thorsten Ottosen" wrote:
| > ""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
| > news:422e00a6$0$11094$3b214f66@usenet.univie.ac.at...
| >
| >| Sorry for answering late.
| >|
| >| What on earth is the usefullness of null-references?
| >
| > well, you can say something like
| >
| > vector<int> foo;
| > .
| > int* end = &*end();
|
| *end() remains undefined even if null/empty references can exist.
really? According to
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232
" If the pointer is a null pointer value (4.10 conv.ptr) or points one past
the last element of an array object (5.7 expr.add), the result is an empty
lvalue "
the motivation is explicitly to allow
char a[10];
char *b = &a[10]; // equivalent to "char *b = &*(a+10);"
br
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (Llewelly)
Date: Sat, 12 Mar 2005 03:31:51 GMT Raw View
nesotto@cs.auc.dk ("Thorsten Ottosen") writes:
> "Ben Hutchings" <ben-public-nospam@decadentplace.org.uk> wrote in message
> news:slrnd32tap.3k7.ben-public-nospam@decadentplace.org.uk...
> | "Thorsten Ottosen" wrote:
> | > ""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
> | > news:422e00a6$0$11094$3b214f66@usenet.univie.ac.at...
> | >
> | >| Sorry for answering late.
> | >|
> | >| What on earth is the usefullness of null-references?
> | >
> | > well, you can say something like
> | >
> | > vector<int> foo;
> | > .
> | > int* end = &*end();
> |
> | *end() remains undefined even if null/empty references can exist.
>
> really? According to
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232
>
> " If the pointer is a null pointer value (4.10 conv.ptr) or points one past
> the last element of an array object (5.7 expr.add), the result is an empty
> lvalue "
>
> the motivation is explicitly to allow
>
> char a[10];
> char *b = &a[10]; // equivalent to "char *b = &*(a+10);"
>
[snip]
But Ben's claim is about vector<int>::iterator - *not* about pointers.
What does the resolution say about iterators? Nothing, AFAICT.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nesotto@cs.auc.dk ("Thorsten Ottosen")
Date: Sat, 12 Mar 2005 16:17:25 GMT Raw View
"Llewelly" <llewelly.at@xmission.dot.com> wrote in message
news:86k6od3gk8.fsf@zorthluthik.foo.bar...
| > the motivation is explicitly to allow
| >
| > char a[10];
| > char *b = &a[10]; // equivalent to "char *b = &*(a+10);"
| >
| [snip]
|
| But Ben's claim is about vector<int>::iterator - *not* about pointers.
| What does the resolution say about iterators? Nothing, AFAICT.
but *end() returns a empty lvalue (reference) to the element one past the last
element.
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Ron Natalie <ron@sensor.com>
Date: Sat, 12 Mar 2005 17:08:44 CST Raw View
Thorsten Ottosen wrote:
> "Llewelly" <llewelly.at@xmission.dot.com> wrote in message
> news:86k6od3gk8.fsf@zorthluthik.foo.bar...
>
> | > the motivation is explicitly to allow
> | >
> | > char a[10];
> | > char *b = &a[10]; // equivalent to "char *b = &*(a+10);"
> | >
> | [snip]
> |
> | But Ben's claim is about vector<int>::iterator - *not* about pointers.
> | What does the resolution say about iterators? Nothing, AFAICT.
>
> but *end() returns a empty lvalue (reference) to the element one past the last
> element.
>
It doesn't return anything deterministic, it's undefined behavior.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Thomas Mang" <nospam@nospam.ucar.edu>
Date: Sat, 12 Mar 2005 23:54:30 CST Raw View
""Thorsten Ottosen"" <nesotto@cs.auc.dk> schrieb im Newsbeitrag
news:4231b354$0$29283$14726298@news.sunsite.dk...
> "Ben Hutchings" <ben-public-nospam@decadentplace.org.uk> wrote in message
> news:slrnd32tap.3k7.ben-public-nospam@decadentplace.org.uk...
> | "Thorsten Ottosen" wrote:
> | > ""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
> | > news:422e00a6$0$11094$3b214f66@usenet.univie.ac.at...
> | >
> | >| Sorry for answering late.
> | >|
> | >| What on earth is the usefullness of null-references?
> | >
> | > well, you can say something like
> | >
> | > vector<int> foo;
> | > .
> | > int* end = &*end();
> |
> | *end() remains undefined even if null/empty references can exist.
>
> really? According to
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232
>
> " If the pointer is a null pointer value (4.10 conv.ptr) or points one
past
> the last element of an array object (5.7 expr.add), the result is an
empty
> lvalue "
And according to what is vec.end() (or deque.end() or map.end()...) either
one of them?
24.1/5 would definitely need a modification too. Probably input/output
iterators need to be made special.
What about templates and the unknown type (as array element) overloads
operator& which performs an rvalue conversion? What about breaking current
iterator libraries that count on not dereferencing the one-past-the-end
iterator? What about the less experienced programmers?
Looks to me a bit because there is currently a little mess, in order to get
homogeneity everything is turned into a total mess.
Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Thorsten Ottosen" <nesotto@cs.auc.dk>
Date: Wed, 16 Mar 2005 15:59:54 CST Raw View
<kuyper@wizard.net> wrote in message
news:1110949349.176045.277260@z14g2000cwz.googlegroups.com...
| "Thorsten Ottosen" wrote:
| > well, we are not discussing the current standard; we're discussing
| the
| > impact on empty lvalues.
|
| But *end() is not, under the current proposal, guaranteed to be an
| empty lvalue. It might be, but the proposal doesn't specify that it is.
|
| > | > 3. hence, *end() gives a reference to one-past the last element.
| > |
| > | The behavior of *end() is undefined.
| >
| > currently, yes. but that is not important.
|
| The proposal under discusion contains nothing that changes that fact.It
| talks about lvalues that refer to a position one past the end of an
| array. end() returns an iterator that is a past-the-end value for the
| container; there's no requirement that *end() be an lvalue referring to
| a location one past the end of an array. For instance, a perfectly
| legal implementation of std::vector<> could always (or at least
| usually) allocate an array at least one position larger than needed
| for the current size. end() could return an iterator pointing into that
| array, rather than one past its end.
well, then *end() it is a valid lvalue, so what's the problem.
| > no, but how will you implement vector<T>::end() if not by using a
| > pointer (direcly or indirectly)?
|
| If it uses the pointer indirectly (i.e. as a member of a an iterator
| class) then the iterator can have quite different properties from the
| contained pointer. In fact, if an implementation chooses to use a
| pointer only indirectly, it's generally for precisely that reason, to
| impose different behavior than the pointer itself would have.
it's to avoid the subset of operations that pointers have but iterators have
not,
i.e. it's a type-safety issue.
| In
| particular, operator*() could have quite different properties when
| acting on the iterator returned by end(), than *p would have on the
| pointer contained in that iterator.
Can we agree that it would be trivial to guarantee that
vector<T>::end() can be dereferenced and produce an
empty lvalue *if the empty lvalue is added to the language*?
If so, we have nothing more to discuss.
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (Llewelly)
Date: Thu, 17 Mar 2005 19:46:58 GMT Raw View
"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
[snip]
> Can we agree that it would be trivial to guarantee that
> vector<T>::end() can be dereferenced and produce an
> empty lvalue *if the empty lvalue is added to the language*?
[snip]
The language you have pointed to, as far as I can see, contains no
such provision.
I will agree that if dereferencing a past the end pointer is to result
in an empty lvalue, the semantics for iterators should be extended
in an equivalent way. However, I do *not* agree that the proposal
to which you prefer contains any such provision.
IMO, if dereferencing a past-then-end iterators is to result in an
empty lvalue, *all* iterators for whom unary * returns an lvalue
should have that semantic, not just vector<T>::iterator.
Similarity between pointers and iterators should not arise simply
becuase vector<T>::iterator happens to be a typedef for T* (or a
thin wrapper) on some implementations; it should be written into
the standard in order to explicitly maintian the strong conceptual
similarity between pointers and iterators.
(Somebody in another thread made the suggestion that the library
working group and the core working group should trade places one
day, and attempt to resolve each others issues. It seems to me
that if this had happened, language similar to that proposed for
core issue 232 might have been written for iterators as well.)
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nospam@nospam.ucar.edu ("Thomas Mang")
Date: Sun, 20 Mar 2005 05:55:00 GMT Raw View
"Thorsten Ottosen" <nesotto@cs.auc.dk> schrieb im Newsbeitrag
news:4238a9c5$0$29278$14726298@news.sunsite.dk...
> <kuyper@wizard.net> wrote in message
> | The proposal under discusion contains nothing that changes that fact.It
> | talks about lvalues that refer to a position one past the end of an
> | array. end() returns an iterator that is a past-the-end value for the
> | container; there's no requirement that *end() be an lvalue referring to
> | a location one past the end of an array. For instance, a perfectly
> | legal implementation of std::vector<> could always (or at least
> | usually) allocate an array at least one position larger than needed
> | for the current size. end() could return an iterator pointing into that
> | array, rather than one past its end.
>
> well, then *end() it is a valid lvalue, so what's the problem.
The problem is 24.1/5 [plus the fact there is no array when dealing with
vector].
> | In
> | particular, operator*() could have quite different properties when
> | acting on the iterator returned by end(), than *p would have on the
> | pointer contained in that iterator.
>
> Can we agree that it would be trivial to guarantee that
> vector<T>::end() can be dereferenced and produce an
> empty lvalue *if the empty lvalue is added to the language*?
I can't agree with that [ :-) ], unless you can point me to the para in the
hypothetical new Standard (based on the current proposal) which overrules
24.1/5, and which says vec.end() is either a null-pointer value, or
one-past-the-end of an array. I am pretty convinced the first sentence of
24.1/1 in combination with the knowledge that vector-iterators are
random-access-iterators can be used for that.
How would you interpret dereferencing the end()-iterator of another
container like list, or set? Undefined behavior, or empty lvalue?
If empty lvalue, based on what?
Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Thorsten Ottosen" <nesotto@cs.auc.dk>
Date: Sun, 20 Mar 2005 12:58:18 CST Raw View
""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
news:4238bb30$0$11352$3b214f66@usenet.univie.ac.at...
| How would you interpret dereferencing the end()-iterator of another
| container like list, or set? Undefined behavior, or empty lvalue?
| If empty lvalue, based on what?
undefined behavior is fine IMO.
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: squell@alumina.nl (Marc Schoolderman)
Date: Sun, 20 Mar 2005 18:49:37 GMT Raw View
> I will agree that if dereferencing a past the end pointer is to result
> in an empty lvalue, the semantics for iterators should be extended
> in an equivalent way.
Why? You can't do anything with such an lvalue than take its address.
Which is a totally useless value, unless you're dealing with a vector,
and there's a good alternative syntax in that case.
Currently, library implementors are allowed to throw an exception when a
user tries to dereference the past-the-end iterator, and this would be a
Good Thing. Forcing past-the-end iterators to be dereferenceable would
make that non-conforming, letting possibly undefined behaviour slip into
user-code instead of being able to catch it in operator*().
> it should be written into
> the standard in order to explicitly maintian the strong conceptual
> similarity between pointers and iterators.
Iterators are not pointers. You can't decrement a forward iterator. You
can't even do "iterator arithmetic" on input/output iterators. Why
should past-the-end iterators be dereferenceable because pointers are?
~Marc.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (Llewelly)
Date: Mon, 21 Mar 2005 04:14:42 GMT Raw View
squell@alumina.nl (Marc Schoolderman) writes:
> > I will agree that if dereferencing a past the end pointer is to result
> > in an empty lvalue, the semantics for iterators should be extended
> > in an equivalent way.
>
> Why? You can't do anything with such an lvalue than take its
> address. Which is a totally useless value, unless you're dealing with
> a vector, and there's a good alternative syntax in that case.
Consistency.
Notice my condition: 'if dereferencing a past the end pointer is to
result in an empty lvalue ...'
I'd prefer the current levels of similarity between iterators and
pointers be maintained. (The empty lvalue feature does not seem to
have any value of its own, IMO.)
>
> Currently, library implementors are allowed to throw an exception when
> a user tries to dereference the past-the-end iterator, and this would
> be a Good Thing. Forcing past-the-end iterators to be dereferenceable
> would make that non-conforming, letting possibly undefined behaviour
> slip into user-code instead of being able to catch it in
> operator*().
I agree with all of this, so long as the status quo w.r.t. empty
lvalues (i.e, they don't exist) remains.
>
> > it should be written into
> > the standard in order to explicitly maintian the strong conceptual
> > similarity between pointers and iterators.
>
> Iterators are not pointers.
Saying there are similarities which should be maintianed is not the
same as saying they are or should be identical.
> You can't decrement a forward
> iterator. You can't even do "iterator arithmetic" on input/output
> iterators. Why should past-the-end iterators be dereferenceable
> because pointers are?
The 'strong conceptual similarity' I was referring to comes from the
similar syntax and semantics used when dereferencing pointers and
iterators. So, 'can't decrement a forward iterator' is not
significant barrier to that similarity, but having one of them
support dereferencing past-the-end values and the other not, would
be a barrier.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (Llewelly)
Date: Tue, 22 Mar 2005 20:41:20 GMT Raw View
"Thorsten Ottosen" <nesotto@cs.auc.dk> writes:
> ""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
> news:4238bb30$0$11352$3b214f66@usenet.univie.ac.at...
>
> | How would you interpret dereferencing the end()-iterator of another
> | container like list, or set? Undefined behavior, or empty lvalue?
> | If empty lvalue, based on what?
>
> undefined behavior is fine IMO.
[snip]
So, you're suggesting some iterators - vector<>::iterator being one
example - have the empty lvalue property, but others don't?
If that's to be the case, it would need to be worked into the iterator
concepts somehow, it seems to me.
That's starting to look like a fair amount of complication for empty
lvalues. Maybe they aren't worth it.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: squell@alumina.nl (Marc Schoolderman)
Date: Tue, 22 Mar 2005 20:41:26 GMT Raw View
Llewelly wrote:
>>Currently, library implementors are allowed to throw an exception when
>>a user tries to dereference the past-the-end iterator, and this would
>>be a Good Thing. Forcing past-the-end iterators to be dereferenceable
>>would make that non-conforming, letting possibly undefined behaviour
>>slip into user-code instead of being able to catch it in
>>operator*().
> I agree with all of this, so long as the status quo w.r.t. empty
> lvalues (i.e, they don't exist) remains.
Judging from issues #232 and #453 (and the discussions therein), the
status quo will just get strengthened, so we're probably in agreement?
Basically, under the proposals,
int& a = array[size]; // undefined (binding to an empty lvalue)
int& b = *vec.end(); // undefined call to operator* (probably)
Which is the kind of consistency we want?
I don't think allowing just limited forms like "&array[size]" (like C99
has) introduces any problematic inconsistency, though.
> The 'strong conceptual similarity' I was referring to comes from the
> similar syntax and semantics used when dereferencing pointers and
> iterators. So, 'can't decrement a forward iterator' is not
> significant barrier to that similarity, but having one of them
> support dereferencing past-the-end values and the other not, would
> be a barrier.
OTOH, since you shouldn't assume that past-the-end iterators are
dereferenceable, it wouldn't really matter if some were. Just as it
doesn't really matter that for some output iterators, *p == p.
~Marc
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: a9804814weg@unet.univie.ac.atweg ("Thomas Mang")
Date: Tue, 22 Mar 2005 20:41:11 GMT Raw View
""Thomas Mang"" <nospam@nospam.ucar.edu> schrieb im Newsbeitrag
news:4238bb30$0$11352$3b214f66@usenet.univie.ac.at...
> I can't agree with that [ :-) ], unless you can point me to the para in
the
> hypothetical new Standard (based on the current proposal) which overrules
> 24.1/5, and which says vec.end() is either a null-pointer value, or
> one-past-the-end of an array. I am pretty convinced the first sentence of
> 24.1/1 in combination with the knowledge that vector-iterators are
> random-access-iterators can be used for that.
The last sentence has, of course, the wrong boolean value and should read:
"I am pretty convinced the first sentence of 24.1/1 CANNOT be used for
that".
sorry,
Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nagle@animats.com (John Nagle)
Date: Wed, 23 Mar 2005 07:49:08 GMT Raw View
Marc Schoolderman wrote:
>> The 'strong conceptual similarity' I was referring to comes from the
>> similar syntax and semantics used when dereferencing pointers and
>> iterators. So, 'can't decrement a forward iterator' is not
>> significant barrier to that similarity, but having one of them
>> support dereferencing past-the-end values and the other not, would
>> be a barrier.
Actually, iterators have considerably more restrictive
semantics than pointers. Which is good. For example,
vector<int> tab;
vector<int>::iterator p = tab.end();
p++; // ILLEGAL
Pointers are allowed to take on arbitrary values,
as long as they're not dereferenced. Iterators are not.
And for iterators, some legal values are not dereferenceable.
There are implementations that check iterators, so those
rules have teeth.
John Nagle
Animats
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: johnchx2@yahoo.com
Date: Wed, 23 Mar 2005 01:48:51 CST Raw View
Llewelly wrote:
> I'd prefer the current levels of similarity between iterators and
> pointers be maintained. (The empty lvalue feature does not seem to
> have any value of its own, IMO.)
But the current level of similarity is simply "pointers (into arrays)
fulfill all the requirements of random-access iterators." Giving
defined meaning to dereferencing the off-the-end-of-the-array pointer
doesn't change that.
It *would* affect reasoning in the "other direction," i.e. the
assumption that "if I can do X to a pointer, then I can do it to any
iterator," but that was never sound in the first place. Nor, for the
most part, is reasoning from arrays to vectors.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: llewelly.at@xmission.dot.com (Llewelly)
Date: Mon, 14 Mar 2005 19:05:12 GMT Raw View
nesotto@cs.auc.dk ("Thorsten Ottosen") writes:
> "Llewelly" <llewelly.at@xmission.dot.com> wrote in message
> news:86k6od3gk8.fsf@zorthluthik.foo.bar...
>
> | > the motivation is explicitly to allow
> | >
> | > char a[10];
> | > char *b = &a[10]; // equivalent to "char *b = &*(a+10);"
> | >
> | [snip]
> |
> | But Ben's claim is about vector<int>::iterator - *not* about pointers.
> | What does the resolution say about iterators? Nothing, AFAICT.
>
> but *end() returns a empty lvalue (reference) to the element one past the last
> element.
Why do you make that claim?
If you have additional information which says that dereferencing a
past-the-end iterator results in an empty lvalue, I would
appreciate it if you would post a link to this information.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: "Thorsten Ottosen" <nesotto@cs.auc.dk>
Date: Mon, 14 Mar 2005 17:30:29 CST Raw View
"Llewelly" <llewelly.at@xmission.dot.com> wrote in message
news:86br9m3m08.fsf@zorthluthik.foo.bar...
| nesotto@cs.auc.dk ("Thorsten Ottosen") writes:
|
| > "Llewelly" <llewelly.at@xmission.dot.com> wrote in message
| > news:86k6od3gk8.fsf@zorthluthik.foo.bar...
| >
| > | > the motivation is explicitly to allow
| > | >
| > | > char a[10];
| > | > char *b = &a[10]; // equivalent to "char *b = &*(a+10);"
| > | >
| > | [snip]
| > |
| > | But Ben's claim is about vector<int>::iterator - *not* about pointers.
| > | What does the resolution say about iterators? Nothing, AFAICT.
| >
| > but *end() returns a empty lvalue (reference) to the element one past the
last
| > element.
|
| Why do you make that claim?
|
| If you have additional information which says that dereferencing a
| past-the-end iterator results in an empty lvalue, I would
| appreciate it if you would post a link to this information.
I'm sure we must be misunderstanding each-other; or at least I must be
misundertanding
you all. Here'show I reason
1. A vector uses heap-allocated arrays to hold its data; Assume the vector is
not empty.
2. end() gives an iterator to one-past the last element
3. hence, *end() gives a reference to one-past the last element
4. AFAICT, the core working group wants to make this legal by mandating that
*end() is an empty lvalue
5. we can take the address of an empty lvalue
which one did I go wrong on?
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: Ian McCulloch <ianmcc@physik.rwth-aachen.de>
Date: Mon, 14 Mar 2005 18:45:37 CST Raw View
Thorsten Ottosen wrote:
> "Llewelly" <llewelly.at@xmission.dot.com> wrote in message
> news:86br9m3m08.fsf@zorthluthik.foo.bar...
> | nesotto@cs.auc.dk ("Thorsten Ottosen") writes:
[snip]
> | > but *end() returns a empty lvalue (reference) to the element one past
> | > the
> last
> | > element.
> |
> | Why do you make that claim?
> |
> | If you have additional information which says that dereferencing a
> | past-the-end iterator results in an empty lvalue, I would
> | appreciate it if you would post a link to this information.
>
> I'm sure we must be misunderstanding each-other; or at least I must be
> misundertanding
> you all. Here'show I reason
>
> 1. A vector uses heap-allocated arrays to hold its data; Assume the vector
> is not empty.
> 2. end() gives an iterator to one-past the last element
> 3. hence, *end() gives a reference to one-past the last element
Does point 3 really follow from 2 ? It would for sure if the iterators were
pointers, but that is not necessarily true. eg, I would expect a debugging
version of the std lib to flag an error on *end().
> 4. AFAICT, the core working group wants to make this legal by mandating
> that
> *end() is an empty lvalue
Is this true for all containers, or just vector? If its only for vector,
then why is vector special? If its for all containers, simply 'why' ?
> 5. we can take the address of an empty lvalue
>
> which one did I go wrong on?
>
> -Thorsten
Cheers,
Ian
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: Mon, 14 Mar 2005 22:21:13 CST Raw View
Thorsten Ottosen wrote:
> "Llewelly" <llewelly.at@xmission.dot.com> wrote in message
> news:86br9m3m08.fsf@zorthluthik.foo.bar...
> | nesotto@cs.auc.dk ("Thorsten Ottosen") writes:
> |
> | > "Llewelly" <llewelly.at@xmission.dot.com> wrote in message
> | > news:86k6od3gk8.fsf@zorthluthik.foo.bar...
> | >
> | > | > the motivation is explicitly to allow
> | > | >
> | > | > char a[10];
> | > | > char *b = &a[10]; // equivalent to "char *b = &*(a+10);"
> | > | >
> | > | [snip]
> | > |
> | > | But Ben's claim is about vector<int>::iterator - *not* about
pointers.
> | > | What does the resolution say about iterators? Nothing, AFAICT.
> | >
> | > but *end() returns a empty lvalue (reference) to the element one
past the
> last
> | > element.
> |
> | Why do you make that claim?
> |
> | If you have additional information which says that dereferencing a
> | past-the-end iterator results in an empty lvalue, I would
> | appreciate it if you would post a link to this information.
>
> I'm sure we must be misunderstanding each-other; or at least I must
be
> misundertanding you all. Here'show I reason
>
> 1. A vector uses heap-allocated arrays to hold its data; Assume the
vector is
> not empty.
That's only true for std::vector<T,Allocator> Allocator allocates from
the heap.
> 2. end() gives an iterator to one-past the last element
The standard's term is "past-the-end value". The defined
characteristics of "past-the-end iterator values are provided in
24.1.1p5. They do not include being derefernceable, nor do the
container requirements impose derefrenceability as a post-condition of
end().
> 3. hence, *end() gives a reference to one-past the last element.
The behavior of *end() is undefined.
> 4. AFAICT, the core working group wants to make this legal by
mandating that
> *end() is an empty lvalue
No, they want to make *p, where p is a pointer one past the end of an
array, be an empty lvalue. The proposal says nothing about *i, where i
is a non-pointer iterator pointing past the end of a vector. A pointer
type can be an iterator, but not all iterators are pointers.
> 5. we can take the address of an empty lvalue
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nesotto@cs.auc.dk ("Thorsten Ottosen")
Date: Tue, 15 Mar 2005 16:25:07 GMT Raw View
<kuyper@wizard.net> wrote in message
news:1110854918.671024.268680@o13g2000cwo.googlegroups.com...
|
| Thorsten Ottosen wrote:
| > I'm sure we must be misunderstanding each-other; or at least I must
| be
| > misundertanding you all. Here'show I reason
| >
| > 1. A vector uses heap-allocated arrays to hold its data; Assume the
| vector is
| > not empty.
|
| That's only true for std::vector<T,Allocator> Allocator allocates from
| the heap.
but the allocator must allocate contiguous storage; that must be an array
whether on the heap or on the stack.
| > 2. end() gives an iterator to one-past the last element
|
| The standard's term is "past-the-end value". The defined
| characteristics of "past-the-end iterator values are provided in
| 24.1.1p5. They do not include being derefernceable, nor do the
| container requirements impose derefrenceability as a post-condition of
| end().
well, we are not discussing the current standard; we're discussing the
impact on empty lvalues.
| > 3. hence, *end() gives a reference to one-past the last element.
|
| The behavior of *end() is undefined.
currently, yes. but that is not important.
| > 4. AFAICT, the core working group wants to make this legal by
| mandating that
| > *end() is an empty lvalue
|
| No, they want to make *p, where p is a pointer one past the end of an
| array, be an empty lvalue. The proposal says nothing about *i, where i
| is a non-pointer iterator pointing past the end of a vector. A pointer
| type can be an iterator, but not all iterators are pointers.
no, but how will you implement vector<T>::end() if not by using a
pointer (direcly or indirectly)?
"Ian McCulloch" <ianmcc@physik.rwth-aachen.de> wrote in message
news:39mltkF61r5duU1@news.dfncis.de...
| Is this true for all containers, or just vector? If its only for vector,
| then why is vector special? If its for all containers, simply 'why' ?
It can only be true for containers with contiguous storage.
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: kuyper@wizard.net
Date: Wed, 16 Mar 2005 14:02:41 CST Raw View
"Thorsten Ottosen" wrote:
> <kuyper@wizard.net> wrote in message
> news:1110854918.671024.268680@o13g2000cwo.googlegroups.com...
> |
> | Thorsten Ottosen wrote:
>
> | > I'm sure we must be misunderstanding each-other; or at least I
must
> | be
> | > misundertanding you all. Here'show I reason
> | >
> | > 1. A vector uses heap-allocated arrays to hold its data; Assume
the
> | vector is
> | > not empty.
> |
> | That's only true for std::vector<T,Allocator> if Allocator
allocates from
> | the heap.
>
> but the allocator must allocate contiguous storage; that must be an
array
> whether on the heap or on the stack.
Well, yes. That's precisely my point. "Allocator allocates from the
heap." is false. It can also allocate from the stack. Also, keep in
mind that multiple heaps and stacks are allowed, and that those aren't
the only possible ways of organizing the memory available to a program.
Of course, none of this affects the rest of your argument; I was just
making a side comment correcting your statement.
> | The standard's term is "past-the-end value". The defined
> | characteristics of "past-the-end iterator values are provided in
> | 24.1.1p5. They do not include being derefernceable, nor do the
> | container requirements impose derefrenceability as a post-condition
of
> | end().
>
> well, we are not discussing the current standard; we're discussing
the
> impact on empty lvalues.
But *end() is not, under the current proposal, guaranteed to be an
empty lvalue. It might be, but the proposal doesn't specify that it is.
> | > 3. hence, *end() gives a reference to one-past the last element.
> |
> | The behavior of *end() is undefined.
>
> currently, yes. but that is not important.
The proposal under discusion contains nothing that changes that fact.It
talks about lvalues that refer to a position one past the end of an
array. end() returns an iterator that is a past-the-end value for the
container; there's no requirement that *end() be an lvalue referring to
a location one past the end of an array. For instance, a perfectly
legal implementation of std::vector<> could always (or at least
usually) allocate an array at least one position larger than needed
for the current size. end() could return an iterator pointing into that
array, rather than one past its end.
> | > 4. AFAICT, the core working group wants to make this legal by
> | mandating that
> | > *end() is an empty lvalue
> |
> | No, they want to make *p, where p is a pointer one past the end of
an
> | array, be an empty lvalue. The proposal says nothing about *i,
where i
> | is a non-pointer iterator pointing past the end of a vector. A
pointer
> | type can be an iterator, but not all iterators are pointers.
>
> no, but how will you implement vector<T>::end() if not by using a
> pointer (direcly or indirectly)?
If it uses the pointer indirectly (i.e. as a member of a an iterator
class) then the iterator can have quite different properties from the
contained pointer. In fact, if an implementation chooses to use a
pointer only indirectly, it's generally for precisely that reason, to
impose different behavior than the pointer itself would have. In
particular, operator*() could have quite different properties when
acting on the iterator returned by end(), than *p would have on the
pointer contained in that iterator.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nesotto@cs.auc.dk ("Thorsten Ottosen")
Date: Tue, 1 Mar 2005 02:18:49 GMT Raw View
""Thomas Mang"" <nospam@nospam.ucar.edu> wrote in message
news:4220f20a$0$12126$3b214f66@usenet.univie.ac.at...
|
| ""Thorsten Ottosen"" <nesotto@cs.auc.dk> schrieb im Newsbeitrag
| > the standard is going to change on this matter; the lates from the October
| > meeting says that
| I don't get this. First, I was shocked when I read that modifications. Now I
| have the hope I am simply misunderstanding what it means.
|
| Could you please provide real-world examples what an empty lvalue etc. is,
| and how it is intended to be used?
int* p = 0;
..
int& r = *p;
..
if( &r != 0 )
{
r = 5;
}
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: moy@polyspace.com (Yannick Moy)
Date: Thu, 3 Mar 2005 06:27:23 GMT Raw View
Do you know what will be the semantics of a dynamic_cast on a null
reference then ? e.g.:
A* p = 0;
A& r = *p;
B& r2 = dynamic_cast<B&>(r);
The standard says so far:
"If the value of v is a null pointer value in the pointer case, the
result is the null pointer value of type R."
Will this translate to:
"If the value of v is a null reference in the reference case, the
result is the null reference value of type R."
Thanks.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: ron@sensor.com (Ron Natalie)
Date: Fri, 18 Feb 2005 02:52:48 GMT Raw View
Yannick Moy wrote:
> The problem is that it is way too easy to create a null reference,
> without any "bad" cast or overflow on a stack array ...
> e.g. the following:
>
> int& r = *p; // with p of type int*
To validate this the compiler would have to check the nullness of
p when doing the initialization. When that might happen is dubious
because at runtime there might not even be any concrete "r" variable
that gets initialized. The compiler in many cases just substitutes
the *p consruct wherever r is used.
You'd have a hard time getting the cycle counters to agree to an
explicit null check here anymore than any other use of *p.
>
> Nobody says here p should not be null, and although the standard
> considers this as a bad operation if p is null, compilers will store
> the possibly null address contained in p into r. (Are there any
> compilers that would crash at run-time on such a construct ?)
There's no indication that anything has to be stored at all.
> Why not prevent this by allowing to bind references only to
> non-dereferenced expressions, so that the previous line becomes
> invalid C++ ?
Fine if you're talking about ints. A little bit more onerous with
larger types (which is presumbaly why you were dealing with pointers
and references anyhow).
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: moy@polyspace.com (Yannick Moy)
Date: Fri, 18 Feb 2005 14:39:28 GMT Raw View
Ron Natalie wrote:
> You'd have a hard time getting the cycle counters to agree to an
> explicit null check here anymore than any other use of *p.
A use of int& or class S& is not part of the C core of C++.
We can expect some more robust treatment from the language and
compilers on a reference that on raw pointers, don't you think ?
Moreover, this null check would be there only when a reference is
taken from a dereferenced raw pointer, that's all.
> There's no indication that anything has to be stored at all.
I agree, the goal of the check is to maintain the invariant that
references do not hold null pointers, whatever the translation of
these references by the compiler is.
> > Why not prevent this by allowing to bind references only to
> > non-dereferenced expressions, so that the previous line becomes
> > invalid C++ ?
> Fine if you're talking about ints. A little bit more onerous with
> larger types (which is presumbaly why you were dealing with pointers
> and references anyhow).
What about a simple function object ?
template <class T> struct reference_cast {
T& operator()(T* p) {
if (p == 0) throw std::bad_cast();
return *p;
}
};
You would use it simply like:
int& r = reference_cast<int>()(p); // for int
S& r = reference_cast<S>()(p); // for S
with no copy-constructor involved.
Maybe it is preferable in this case to make the operator() inline ?
Then if the compiler knows that (p == 0) is always false, it can
safely remove the check, which makes the program as simple as the
original
int& r = *p;
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: johnchx2@yahoo.com
Date: Sat, 19 Feb 2005 01:44:51 CST Raw View
Yannick Moy wrote:
> The problem is that it is way too easy to create a null reference,
> without any "bad" cast or overflow on a stack array ...
> e.g. the following:
>
> int& r = *p; // with p of type int*
>
I think the real problem here is that the code potentially dereferences
a null pointer. It has nothing to do with whether or not you go on to
bind the lvalue to a reference.
So the question really ought to be: how do we ensure that we never
dereference a null pointer?
I think there's something to be said for a coding convention that says
that the *only* reason to dereference a pointer is to initialize a
reference, immediately after explicitly testing that the pointer is
non-null.
Of course there are a few (chuckle) practical difficulties. Do we
really want to outlaw operator->()? What about smart pointers? What
about those C API's that insist on returning pointers but that
guarantee that they are non-null...is a redundant test really
necessary?
But I do think it's worth at least being aware that every pointer
dereferencing operation is making an assumption that is not guaranteed
by the type system, and is therefore hazardous to one's health.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: richard@ex-parrot.com
Date: Tue, 22 Feb 2005 12:57:28 CST Raw View
Yannick Moy wrote:
> What about a simple function object ?
>
> template <class T> struct reference_cast {
> T& operator()(T* p) {
> if (p == 0) throw std::bad_cast();
> return *p;
> }
> };
What's wrong with a simple template function?
template <class T>
T& reference_cast( T* p ) {
/* as before */
}
Much neater -- you don't need the extra paretheses when using it. Or
if you wanted to explicitly prevent template argument deduction (for
example, to require a cast-like syntax), then just do
template <class T>
T& reference_cast( typename boost::mpl::identity<T*>::type p ) {
/* as before */
}
> Maybe it is preferable in this case to make the operator() inline ?
It is inline. Any function defined within the body of the class is
implicitly inline.
--
Richard Smith
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: rogero@howzatt.demon.co.uk ("Roger Orr")
Date: Wed, 23 Feb 2005 21:44:07 GMT Raw View
I'd like to pick up on your last-but-one question:
> Is it a problem that's never seen in real-life code ?
It is seen, sometimes, in my experience. However using a null reference
usually generates an easily debuggable fault.
I think it is less of a problem than dangling references, which cause other
problems like memory corruption.
There is also a problem with calling through a null 'this' pointer:-
p->aMethod();
although 'undefined behaviour' depending on whether 'aMethod()' accesses
instance data it may not cause any apparent grief.
Regards,
Roger Orr
--
MVP in C++ at www.brainbench.com
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nesotto@cs.auc.dk ("Thorsten Ottosen")
Date: Sat, 26 Feb 2005 15:41:24 GMT Raw View
"Yannick Moy" <moy@polyspace.com> wrote in message
news:d45930e4.0502162259.75655cd5@posting.google.com...
| In previous conversations on this newsgroup, it is said that null
| references qualify as "undefined behaviour", as said in standard
| 8.3.2.4:
| "a null reference cannot exist in a well-defined program, because the
| only way to create such a reference would be to bind it to the object
| obtained by dereferencing a null pointer".
the standard is going to change on this matter; the lates from the October
meeting says that
"
Proposed resolution (October, 2004):
(Note: the resolution of issue 453 also resolves part of this issue.)
Add the indicated words to 3.10 basic.lval paragraph 2:
An lvalue refers to an object or function or is an empty lvalue (5.3.1
expr.unary.op).
Add the indicated words to 5.3.1 expr.unary.op paragraph 1:
The unary * operator performs indirection: the expression to which it is
applied shall be a pointer to an object type, or a pointer to a function type
and the result is an lvalue referring to the object or function to which the
expression points, if any. If the pointer is a null pointer value (4.10
conv.ptr) or points one past the last element of an array object (5.7
expr.add), the result is an empty lvalue and does not refer to any object or
function. An empty lvalue is not modifiable. If the type of the expression is
"pointer to T," the type of the result is "T." [Note: a pointer to an
incomplete type (other than cv void) can be dereferenced. The lvalue thus
obtained can be used in limited ways (to initialize a reference, for example);
this lvalue must not be converted to an rvalue, see 4.1 conv.lval.-end note]
Add the indicated words to 4.1 conv.lval paragraph 1:
If the object to which the lvalue refers is not an object of type T and is not
an object of a type derived from T, or if the object is uninitialized, or if
the lvalue is an empty lvalue (5.3.1 expr.unary.op), a program that
necessitates this conversion has undefined behavior.
Change 1.9 intro.execution as indicated:
Certain other operations are described in this International Standard as
undefined (for example, the effect of dereferencing the null pointer division
by zero)"
AFAICT, null references are already allowed on many compilers.
-Thorsten
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: nospam@nospam.ucar.edu ("Thomas Mang")
Date: Sun, 27 Feb 2005 22:00:34 GMT Raw View
""Thorsten Ottosen"" <nesotto@cs.auc.dk> schrieb im Newsbeitrag
news:421c96b2$0$29273$14726298@news.sunsite.dk...
>
>
> "Yannick Moy" <moy@polyspace.com> wrote in message
> news:d45930e4.0502162259.75655cd5@posting.google.com...
> | In previous conversations on this newsgroup, it is said that null
> | references qualify as "undefined behaviour", as said in standard
> | 8.3.2.4:
> | "a null reference cannot exist in a well-defined program, because the
> | only way to create such a reference would be to bind it to the object
> | obtained by dereferencing a null pointer".
>
> the standard is going to change on this matter; the lates from the October
> meeting says that
>
> "
> Proposed resolution (October, 2004):
> (Note: the resolution of issue 453 also resolves part of this issue.)
>
> Add the indicated words to 3.10 basic.lval paragraph 2:
> An lvalue refers to an object or function or is an empty lvalue (5.3.1
> expr.unary.op).
>
> Add the indicated words to 5.3.1 expr.unary.op paragraph 1:
> The unary * operator performs indirection: the expression to which it is
> applied shall be a pointer to an object type, or a pointer to a function
type
> and the result is an lvalue referring to the object or function to which
the
> expression points, if any. If the pointer is a null pointer value (4.10
> conv.ptr) or points one past the last element of an array object (5.7
> expr.add), the result is an empty lvalue and does not refer to any object
or
> function. An empty lvalue is not modifiable. If the type of the expression
is
> "pointer to T," the type of the result is "T." [Note: a pointer to an
> incomplete type (other than cv void) can be dereferenced. The lvalue thus
> obtained can be used in limited ways (to initialize a reference, for
example);
> this lvalue must not be converted to an rvalue, see 4.1 conv.lval.-end
note]
>
> Add the indicated words to 4.1 conv.lval paragraph 1:
> If the object to which the lvalue refers is not an object of type T and is
not
> an object of a type derived from T, or if the object is uninitialized, or
if
> the lvalue is an empty lvalue (5.3.1 expr.unary.op), a program that
> necessitates this conversion has undefined behavior.
>
> Change 1.9 intro.execution as indicated:
> Certain other operations are described in this International Standard as
> undefined (for example, the effect of dereferencing the null pointer
division
> by zero)"
I don't get this. First, I was shocked when I read that modifications. Now I
have the hope I am simply misunderstanding what it means.
Could you please provide real-world examples what an empty lvalue etc. is,
and how it is intended to be used?
Thomas
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]
Author: moy@polyspace.com (Yannick Moy)
Date: Thu, 17 Feb 2005 18:25:02 GMT Raw View
In previous conversations on this newsgroup, it is said that null
references qualify as "undefined behaviour", as said in standard
8.3.2.4:
"a null reference cannot exist in a well-defined program, because the
only way to create such a reference would be to bind it to the object
obtained by dereferencing a null pointer".
The problem is that it is way too easy to create a null reference,
without any "bad" cast or overflow on a stack array ...
e.g. the following:
int& r = *p; // with p of type int*
Nobody says here p should not be null, and although the standard
considers this as a bad operation if p is null, compilers will store
the possibly null address contained in p into r. (Are there any
compilers that would crash at run-time on such a construct ?)
Why not prevent this by allowing to bind references only to
non-dereferenced expressions, so that the previous line becomes
invalid C++ ?
If there is a need for such an operation, either it can be made
explicit that there is a dereference:
int i = *p;
in& r = i;
or, if the object pointed-to must stay at its current location (stack
or heap), or to avoid a copy-constructor if the object pointed-to is
of class type, we can consider a template function object or a
specific reference_cast operator that takes a pointer and returns a
reference to the pointed-to location:
int& r = reference_cast<int&>(p);
This template function object or operator would check that p is not
null, and throw an exception in case it is null.
Is it a problem that's never seen in real-life code ?
Are there other solutions to solve it ?
Thanks.
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html ]