Topic: Q on history of new-style casts


Author: "Andrei Alexandrescu" <andrewalex@hotmail.com>
Date: 2000/06/09
Raw View
Steve Clamage <stephen.clamage@sun.com> wrote in message
news:3936A075.DDAF78B9@sun.com...
> I don't think it is helpful to think of references as const
pointers,
> unless you want to understand implementation details.  As a
> programming construct, references are syntactically and
> semantically different.  Thinking of them as pointers creates
> false expectations and can lead to confusion.

Hmmm, I tend to understand and explain references as pointers that are
always automagically stuck to a * at all times (except for
initailization). This metaphor has never failed me, although I have to
admit I never pushed it too far :o).


Andrei


---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/06/02
Raw View
James Kuyper <kuyper@wizard.net> writes:
> However, a reference is semantically almost identical to a const
> pointer, just with a different syntax.

There are no null references. This is part of the design of C++.
If at any point you take the address of a reference and compare
it to 0, the compiler is completely justified in removing that
test from the generated code. In fact, given the tendency of
programmers to code such tests, this might be one of the most
useful optimizations the compiler could do!

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 2000/06/02
Raw View
In article <8gum4d$s18$1@plutonium.btinternet.com>, Chris Newton
<chrisnewton@no.junk.please.btinternet.com> writes
>Q1: A dynamic_cast throws a std::bad_cast exception if it fails to cast
>with references, but returns a null pointer if it fails to cast with
>pointers. Does anyone know the reason for this apparent inconsistency?

You have it the wrong way round, we would have preferred not to use
exceptions for this problem but it was the only effective way to handle
the reference case.  Using a NULL pointer results in far tidier code in
this case.

>
>Q2: How does this fit with the decision to have new throw a
>std::bad_alloc exception if it fails, and to provide the nothrow set-up
>offering the old-style null pointer return if the programmer prefers?

An allocation failure is always a problem and needs to be handled but
not necessarily where it happens.  It leads to cleaner code and a
greater degree of safety if failure always has to be handled somewhere
and not just left to hoping the programmer remembers to check.


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

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jthill@telus.net (Jim Hill)
Date: 2000/06/02
Raw View
Dave Harris <scorp@btinternet.com> wrote:

> what ... should happen if q is 0

(chiming in with examples:) As it is now, you get your choice:

1) pointer, null:         p = dynamic_cast<X*>(q)
2) pointer, throw:        p = &dynamic_cast<X&>(*q)
3) reference, throw:      r = dynamic_cast<X&>(*q)
4) reference, undefined:  r = *dynamic_cast<X*>(q)

References aren't exactly pointers; and the slight asymmetry here is one
of the few visible results. So I can see how it might surprise, but not
how to improve it...

Jim

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Mark Williams <markw65@my-deja.com>
Date: 2000/06/02
Raw View
In article <1ebjjkl.1c7mlzj4s5uguN%jthill@telus.net>,
  jthill@telus.net (Jim Hill) wrote:
> Dave Harris <scorp@btinternet.com> wrote:
>
> > what ... should happen if q is 0
>
> (chiming in with examples:) As it is now, you get your choice:
>
> 1) pointer, null:         p = dynamic_cast<X*>(q)
> 2) pointer, throw:        p = &dynamic_cast<X&>(*q)
> 3) reference, throw:      r = dynamic_cast<X&>(*q)
> 4) reference, undefined:  r = *dynamic_cast<X*>(q)
>

Both 2 and 3 result in undefined behavior if q is null.

-------------
Mark Williams


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 2000/06/03
Raw View
Steve Clamage wrote:
>
> James Kuyper wrote:
> >
> >
> >  You can even take the address of
> > a reference.
>
> But you don't get the address of the reference; you get the address
> of what it refers to. Examples;
>
> int k;          // k is at at address 0x1234
> int* const p = &k;      // p is at address 0x5678
> int& r = k;
>
> cout << (void*)&p; // prints 0x5678
> cout << (void*)&r; // prints 0x1234
>

In other words, you get the value that would be in the hidden const
pointer that could be used to implement the reference, which is exactly
what I meant.

> Yet another semantic difference between a const pointer and a reference.

No, that's only a syntactic difference. When you match up the syntax
according to the proper equivalence, you get matching semantics.
Syntactically, r is essentially equivalent to *p, &r is essentially
equivalent to p. When you re-write your example to use that equivalence,
the semantics match up:

cout << (void*)p; // prints 0x1234
cout << (void*)&r; // prints 0x1234

There is a difference, of course. The expression &p is legal, but has no
equivalent in terms of r. That's part of why I say that they're only
'essentially' equivalent, rather than exactly equivalent.

> I don't think it is helpful to think of references as const pointers,
> unless you want to understand implementation details.  As a
> programming construct, references are syntactically and
> semantically different.  Thinking of them as pointers creates
> false expectations and can lead to confusion.

I don't think I've had any false expectations yet, nor confusions. My
point was that the semantic differences between r and *p were not
necessary; they were deliberate decisions, not forced by difficulties in
implementation. The only reason that &r can never legally be a null
pointer is that the committee decided that it should be illegal, not
because it would be difficult to arrange. You can't actually enter a
block of code where a reference has been initialized by a failed
dynamic_cast<>, because it throws an exception. That's a neat and subtle
way of enforcing what a reference means; but it wasn't the only way it
could have been done.

I'm not saying they were bad decisions. I may have caused some
confusion, by hinting at this without explicitly commenting on the
reasons for those decisions. Everything I could say about the reasons
would be guesses based upon reverse engineering. I'm pretty good at
reverse engineering designs, but I was hoping to provoke comment about
them from someone who was involved in the actual forward engineering.

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: wmm@fastdial.net
Date: 2000/06/03
Raw View
In article <3937B924.A1EAAB7F@wizard.net>,
  James Kuyper <kuyper@wizard.net> wrote:
> Steve Clamage wrote:
> >
> > I don't think it is helpful to think of references as const
pointers,
> > unless you want to understand implementation details.  As a
> > programming construct, references are syntactically and
> > semantically different.  Thinking of them as pointers creates
> > false expectations and can lead to confusion.
>
> I don't think I've had any false expectations yet, nor confusions. My
> point was that the semantic differences between r and *p were not
> necessary; they were deliberate decisions, not forced by difficulties
in
> implementation. The only reason that &r can never legally be a null
> pointer is that the committee decided that it should be illegal, not
> because it would be difficult to arrange. You can't actually enter a
> block of code where a reference has been initialized by a failed
> dynamic_cast<>, because it throws an exception. That's a neat and
subtle
> way of enforcing what a reference means; but it wasn't the only way it
> could have been done.
>
> I'm not saying they were bad decisions. I may have caused some
> confusion, by hinting at this without explicitly commenting on the
> reasons for those decisions. Everything I could say about the reasons
> would be guesses based upon reverse engineering. I'm pretty good at
> reverse engineering designs, but I was hoping to provoke comment about
> them from someone who was involved in the actual forward engineering.

The decision about "null references" really has its roots in
the original conception of references (i.e., long before the
standardization process began).  For instance, digging out my
1986 copy of _The C++ Programming Language_, 2.3.10 (p56) says,
"A reference is an alternative name for an object...  A
reference must be initialized (there must be something for it
to be a name for)."

C++ goes to some lengths to ensure that there is a valid
object behind every name -- that's the reason for not allowing
jumping past an initialization, for the restrictions on the
order of operations in a constructor, etc.  (The only major
hole in this is the ability to invoke a destructor explicitly
on a named object.)  The treatment of references is an
outgrowth of the same concern.  If you have a reference, you
have an object (unless you do something to cause undefined
behavior like deleting the object to which the reference is
bound).  Breaking this principle didn't (doesn't) seem worth
whatever gain there might be.  If you need "null," use pointers.

A related point: how would you initialize a "null reference"?
It would have to be something like

        int& r = *((int*) 0);

Indirecting through a null pointer, regardless of the context,
doesn't seem like a good idea (as well as violating the
constraint that every reference is initialialized with an
object).

Anyhow, these are some of the considerations that led to the
decision not to allow "null references".  That was ancient
history at the time dynamic_cast was added to the language,
and I don't recall any consideration of revising that earlier
decision when dynamic_cast was being considered.
--
William M. Miller, wmm@fastdial.net
OnDisplay, Inc. (www.ondisplay.com)


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Mark Williams <markw65@my-deja.com>
Date: 2000/06/03
Raw View
In article <3935B398.8D4DE1A8@wizard.net>,
  James Kuyper <kuyper@wizard.net> wrote:
>
> However, a reference is semantically almost identical to a const
> pointer, just with a different syntax. You can even take the address
of
> a reference. Internally, references would almost always be implemented
> by the equivalent of a const pointer. Therefore, it seems reasonable
to
> me to allow &ref to return a null pointer, when ref is a reference
> created by a failed dynamic_cast<>. Example:
>
> void funcpoint(Derived *pd)
> {
>  Base * const pb = dynamic_cast<Base*>pd;
>  if(pb == (Base*)NULL)
>  {
>   // error handling
>  }else{
>   // use *pb
>  }
> }
>
> void funcref(Derived& d)
> {
>  Base &b = dynamic_cast<Base&>d;
>  if(&b == (Base*)NULL)
>  {
>   // error handling
>  }else{
>   // use b
>  }
> }
>
> I'd expect a decent compiler to produce equivalent code for each of
> those functions, if the standard had been written that way. That's not
> what they chose to do, but I can't think of any reason why it wouldn't
> have been feasible. Therefore, the question of why it wasn't done must
> go a little deeper.

Because it would have introduced the concept of null references.

By disallowing null references, the compiler can avoid the checks it
would need for null pointers.

eg when converting a pointer from derived to base, when the base is not
at offset zero within derived, the compiler has to emit an explicit test
for null. With references it does not.

-------------
Mark Williams


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jthill@telus.net (Jim Hill)
Date: 2000/06/04
Raw View
Mark Williams <markw65@my-deja.com> wrote:

> > 2) pointer, throw:        p = &dynamic_cast<X&>(*q)
> > 3) reference, throw:      r = dynamic_cast<X&>(*q)
> Both 2 and 3 result in undefined behavior if q is null.

Ah. I see now that, while 5.2.8 (typeid) says
> If the lvalue expression is obtained by applying the unary * operator to a
> pointer and the pointer is a null pointer value (4.10), the typeid
> expression throws the bad_typeid exception (18.5.3).
5.2.7 (dynamic cast) doesn't have that. My fault: careless reading.

Is there any other part of the language that _can_ check for null
lvalues? The more I think about it, the more startling the notion seems.

Jim

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: jthill@telus.net (Jim Hill)
Date: 2000/06/04
Raw View
Mark Williams <markw65@my-deja.com> wrote:

> Because it would have introduced the concept of null references.

What's the difference between a null reference and a null lvalue? See
<1ebljis.12u3v7uqwi5lcN%jthill@telus.net>: 5.2.8 explicitly allows
typeid to check whether the lvalue itself is derived from a null
pointer. It seems to me dynamic_cast could have the same license - I
thought it did, until you corrected me.

But how on earth does typeid check for an lvalue created from a null
pointer? There's only one way to get that: *(foo*)0 in some guise or
another.

I can answer the question, of course: whatever typeid does can't escape
into the language. But its argument sure looks like a null reference to
me...

Jim

Jim

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: scorp@btinternet.com (Dave Harris)
Date: 2000/06/01
Raw View
wmm@fastdial.net () wrote:
>         try {
>             p = dynamic_cast<X*>(q);
>         }
>         catch (std::bad_cast) { ... }

I think the suggestion is to write something like:

    if ((p = dynamic_cast<X*, no_throw>(q)) != 0)

by analogy with:

    if ((p = new(no_throw) X) != 0)

(If I have the syntax right.) Then the default:

    p = dynamic_cast<X*>(q);

would be like:

    p = new X;

This would arguably be a safer default, as well as more consistent.

However, I am not sure what Chris Newton thinks should happen if q is 0.
It seems unkind to throw, since the null pointer isn't really the fault of
the cast - the cast can convert (Y *)0 into (X *)0 quite successfully.
And yet not to throw means we may have to test p for 0 even if the
throwing cast succeeds. Generally if I have to test for 0, I don't much
care where it came from.

Overall the standard behaviour seems the most convenient, and the
inconsistency doesn't bother me. "A needless consistency is the hobgoblin
of tiny minds", as the fortune cookie puts it.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      brangdon@cix.co.uk      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Chris Newton" <chrisnewton@no.junk.please.btinternet.com>
Date: 2000/06/01
Raw View
<wmm@fastdial.net> wrote [abridged]...
>   "Chris Newton" <chrisnewton@no.junk.please.btinternet.com> wrote:
> > Q1: A dynamic_cast throws a std::bad_cast exception if
> > it fails to cast with references, but returns a null pointer
> > if it fails to cast with pointers. Does anyone know the
> > reason for this apparent inconsistency?

[...]

> The pointer case could have been defined to throw, as
> well, but that seemed somewhat unfriendly.  It's much
>  shorter to write
>
>         if ((p = dynamic_cast<X*>(q)) != 0)
>
> than to write
>
>         try {
>             p = dynamic_cast<X*>(q);
>         }
>         catch (std::bad_cast) { ... }
>
> > Q2: How does this fit with the decision to have new
> > throw a std::bad_alloc exception if it fails, and to
> > provide the nothrow set-up offering the old-style null
> > pointer return if the programmer prefers?
>
> I don't see any relation.

Well, applying the logic you gave above in answer to Q1, it's also much
shorter to write
  if (p = new Q) { ... }
than to write
  try {
    p = new Q;
    ...
  }
  catch (std::bad_alloc) { ... }

I'm sure this point was considered by the standards committee. I was
just curious about why they ultimately decided to have new throw an
exception by default, but dynamic_cast return a null pointer. Using
dynamic_cast with pointers seems somehow the odd-one-out, different from
both other uses of dynamic_cast and other failed pointer assignments.

As I mentioned, this one caught me out the other day - I expected
dynamic_cast to throw on a failed pointer conversion as well. I'd like
to know if the difference was just a quirk of the standardization
process, or whether there was some more significant logic behind it.

Regards,
Chris


---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Hyman Rosen <hymie@prolifics.com>
Date: 2000/06/01
Raw View
"Chris Newton" <chrisnewton@no.junk.please.btinternet.com> writes:
> I'm sure this point was considered by the standards committee. I was
> just curious about why they ultimately decided to have new throw an
> exception by default, but dynamic_cast return a null pointer.

It's never expected that new will fail, so forcing a test for its
return value on every use is bad. Much better to throw an exception
in the rare cases that you run out of memory.

On the other hand, downcasting has no such expectation. Some code
will use downcasts to see whether in fact an inheritance relationship
exists, and other code will use it knowing that such a relationship
exists. Casting to a pointer supports the first type of code, and
casting to a reference supports the second type.

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: vaps4bm@prism.gatech.edu (Brian McNamara!)
Date: 2000/06/01
Raw View
"Chris Newton" <chrisnewton@no.junk.please.btinternet.com> once said:
>I'm sure this point was considered by the standards committee. I was
>just curious about why they ultimately decided to have new throw an
>exception by default, but dynamic_cast return a null pointer. Using

I don't know the actual reasons behind it, but here's some logic that
makes sense to me...

Basically I see two issues: frequency and context.

Frequency: new is called very often, and it should rarely fail.  This
makes an exception a great way to signify failure (it is truly an
exceptional circumstance).  dynamic_cast is called far less frequently,
and will fail far more often.  This makes exceptions less attractive,
as a failed dynamic_cast is less an exceptional circumstance.  (This
now sounds to me like a flimsier argument than it did in my head before
I wrote this paragraph, but I think there's still some merit here.)

Context: it is highly unlikely that a random call to new (which may be
nested in the depths of some random library) has the context
information to know how to deal with failure.  If new returned 0 on
failure, and this was detected, say, inside an allocator for strings,
what would the detecting code do?  Probably just raise an exception
anyway.  A failed dynamic_cast, on the other hand, has a higher
probability of being "in the right context" to deal with the error.

A failed dynamic_cast might not even be an error at all, as in

   if( Foo* f = dynamic_cast<Foo*>( some_widget ) ) {
      f->foo_stuff();
   }
   else if( Bar* b = dynamic_cast<Bar*>( some_widget ) ) {
      b->bar_stuff();
   }

Some may argue that this is bad style, but since dynamic_cast implies a
test, I think it's reasonable to use in conditionals like this.  Thus a
failed dynamic_cast may be perfectly reasonable and meaningful (whereas
a failed new is unlikely to be dealt with so gracefully).


In any case, my overall point is that your question seems to suggest
something like "the language constructs are inconsistent, and they
should be consistent since consistent syntax is nice".  However this
completely ignore the context in which the constructs are used.  Given
than new and dynamic_cast are used very differently in practice, it
seems appropriate that they behave differently, despite the fact that
they have some syntactic similarities.

--
Brian McNamara

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Steve Clamage <stephen.clamage@sun.com>
Date: 2000/06/01
Raw View
Chris Newton wrote:
>
> <wmm@fastdial.net> wrote [abridged]...
> >   "Chris Newton" <chrisnewton@no.junk.please.btinternet.com> wrote:
> > > Q1: A dynamic_cast throws a std::bad_cast exception if
> > > it fails to cast with references, but returns a null pointer
> > > if it fails to cast with pointers. Does anyone know the
> > > reason for this apparent inconsistency?
>
> [...]
>
> > The pointer case could have been defined to throw, as
> > well, but that seemed somewhat unfriendly.  It's much
> >  shorter to write
> >
> >         if ((p = dynamic_cast<X*>(q)) != 0)
> >
> > than to write
> >
> >         try {
> >             p = dynamic_cast<X*>(q);
> >         }
> >         catch (std::bad_cast) { ... }
> >
> > > Q2: How does this fit with the decision to have new
> > > throw a std::bad_alloc exception if it fails, and to
> > > provide the nothrow set-up offering the old-style null
> > > pointer return if the programmer prefers?
> >
> > I don't see any relation.
>
> Well, applying the logic you gave above in answer to Q1, it's also much
> shorter to write
>   if (p = new Q) { ... }
> than to write
>   try {
>     p = new Q;
>     ...
>   }
>   catch (std::bad_alloc) { ... }

It's due to the fundamental difference between references and
pointers. A null pointer is a well-defined language feature.
There is no such thing as a null reference.

If you don't want to deal with exceptions in a dynamic_cast,
cast pointers instead of references.

Similarly, if you don't want to deal with allocation exceptions,
use the no-throw version of a new-expression.
 if ( p = new (nothrow) Q ) { ... }

It would have been possible to specify new-expressions the
other way: The default would be nothrow, and you'd have to
ask for the version that could throw an exception. The C++
Committee discussed this point over a long period, and after
considerable debate concluded that the default behavior should
detect allocation failures proactively.

--
Steve Clamage, stephen.clamage@sun.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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James Kuyper <kuyper@wizard.net>
Date: 2000/06/01
Raw View
wmm@fastdial.net wrote:
>
> In article <8gum4d$s18$1@plutonium.btinternet.com>,
>   "Chris Newton" <chrisnewton@no.junk.please.btinternet.com> wrote:
> > Dear all,
> >
> > This one caught me at work the other day, and I'd like to know the
> > history behind it.
> >
> > Q1: A dynamic_cast throws a std::bad_cast exception if it fails to
> cast
> > with references, but returns a null pointer if it fails to cast with
> > pointers. Does anyone know the reason for this apparent inconsistency?
>
> Yes.  There is a distinguished value, the null pointer, that
> can be used to check whether a pointer cast succeeded or not.
> There is no such way of testing whether a reference cast
> succeeded, because there are no "null references."  The pointer

True.

However, a reference is semantically almost identical to a const
pointer, just with a different syntax. You can even take the address of
a reference. Internally, references would almost always be implemented
by the equivalent of a const pointer. Therefore, it seems reasonable to
me to allow &ref to return a null pointer, when ref is a reference
created by a failed dynamic_cast<>. Example:

void funcpoint(Derived *pd)
{
 Base * const pb = dynamic_cast<Base*>pd;
 if(pb == (Base*)NULL)
 {
  // error handling
 }else{
  // use *pb
 }
}

void funcref(Derived& d)
{
 Base &b = dynamic_cast<Base&>d;
 if(&b == (Base*)NULL)
 {
  // error handling
 }else{
  // use b
 }
}

I'd expect a decent compiler to produce equivalent code for each of
those functions, if the standard had been written that way. That's not
what they chose to do, but I can't think of any reason why it wouldn't
have been feasible. Therefore, the question of why it wasn't done must
go a little deeper.

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Kevlin Henney <kevlin@curbralan.com>
Date: 2000/06/02
Raw View
In article <3935B398.8D4DE1A8@wizard.net>, James Kuyper
<kuyper@wizard.net> writes
>However, a reference is semantically almost identical to a const
>pointer, just with a different syntax.

However, "almost identical" is not the same as "identical".

>You can even take the address of
>a reference. Internally, references would almost always be implemented
>by the equivalent of a const pointer. Therefore, it seems reasonable to
>me to allow &ref to return a null pointer, when ref is a reference
>created by a failed dynamic_cast<>.

I know of at least one compiler that would trap null references (I
believe the Salford compiler does), and this is a debug option I would
like to see available on more compilers. So, not only is there currently
no a concept of null reference, there should never be one.

[...]
>I'd expect a decent compiler to produce equivalent code for each of
>those functions, if the standard had been written that way. That's not
>what they chose to do, but I can't think of any reason why it wouldn't
>have been feasible. Therefore, the question of why it wasn't done must
>go a little deeper.

If you want const pointers you know where to find them ;->
____________________________________________________________

  Kevlin Henney                   phone:  +44 117 942 2990
  Curbralan Ltd                   mobile: +44 7801 073 508
  kevlin@curbralan.com            fax:    +44 870 052 2289
____________________________________________________________

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Chris Newton" <chrisnewton@no.junk.please.btinternet.com>
Date: 2000/05/31
Raw View
Dear all,

This one caught me at work the other day, and I'd like to know the
history behind it.

Q1: A dynamic_cast throws a std::bad_cast exception if it fails to cast
with references, but returns a null pointer if it fails to cast with
pointers. Does anyone know the reason for this apparent inconsistency?

Q2: How does this fit with the decision to have new throw a
std::bad_alloc exception if it fails, and to provide the nothrow set-up
offering the old-style null pointer return if the programmer prefers?

Thanks in advance for your input,
Chris


---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: wmm@fastdial.net
Date: 2000/06/01
Raw View
In article <8gum4d$s18$1@plutonium.btinternet.com>,
  "Chris Newton" <chrisnewton@no.junk.please.btinternet.com> wrote:
> Dear all,
>
> This one caught me at work the other day, and I'd like to know the
> history behind it.
>
> Q1: A dynamic_cast throws a std::bad_cast exception if it fails to
cast
> with references, but returns a null pointer if it fails to cast with
> pointers. Does anyone know the reason for this apparent inconsistency?

Yes.  There is a distinguished value, the null pointer, that
can be used to check whether a pointer cast succeeded or not.
There is no such way of testing whether a reference cast
succeeded, because there are no "null references."  The pointer
case could have been defined to throw, as well, but that seemed
somewhat unfriendly.  It's much shorter to write

        if ((p = dynamic_cast<X*>(q)) != 0)

than to write

        try {
            p = dynamic_cast<X*>(q);
        }
        catch (std::bad_cast) { ... }

> Q2: How does this fit with the decision to have new throw a
> std::bad_alloc exception if it fails, and to provide the nothrow set-
up
> offering the old-style null pointer return if the programmer prefers?

I don't see any relation.
--
William M. Miller, wmm@fastdial.net
OnDisplay, Inc. (www.ondisplay.com)


Sent via Deja.com http://www.deja.com/
Before you buy.

---
[ 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://reality.sgi.com/austern_mti/std-c++/faq.html              ]