nullptr reference legal?

J

Jim Langston

I wound up creating a null reference on accident using polymorphism and
wondered if this snippet is legal code, as it compiles and works as I would
expect it to work.

void jglRenderModel( jglModel& model ) {
if ( &model == nullptr ) {
return;
}
/* ... */
}

// Following line may produce a nullptr reference
jglRenderModel( *dynamic_cast<jmlGL::jglModel*>((world.objects.find(
L"Cube" ))->second) );
// Following line will produce a nullptr reference
jglRenderModel( *reinterpret_cast<jmlGL::jglModel*>( nullptr ) );
 
J

Jim Langston

Jim Langston said:
I wound up creating a null reference on accident using polymorphism and
wondered if this snippet is legal code, as it compiles and works as I would
expect it to work.

void jglRenderModel( jglModel& model ) {
if ( &model == nullptr ) {
return;
}
/* ... */
}

// Following line may produce a nullptr reference
jglRenderModel( *dynamic_cast<jmlGL::jglModel*>((world.objects.find(
L"Cube" ))->second) );
// Following line will produce a nullptr reference
jglRenderModel( *reinterpret_cast<jmlGL::jglModel*>( nullptr ) );

Hmm.. this is dereferencing a nullptr isn't it? So I guess it's illegal.
So I have to wrap the null reference around something just to do what I can
already do. *sigh*
 
M

Marcel Müller

Jim said:
I wound up creating a null reference on accident using polymorphism and
wondered if this snippet is legal code, as it compiles and works as I
would expect it to work.

void jglRenderModel( jglModel& model ) {
if ( &model == nullptr ) {
return;
}
/* ... */
}

This code is valid. However, it makes no sense since &model must not be
NULL.
// Following line may produce a nullptr reference
jglRenderModel( *dynamic_cast<jmlGL::jglModel*>((world.objects.find(
L"Cube" ))->second) );

This code is invalid if and only if the dynamic cast returns nullptr
since you must not dereference a nullptr.
// Following line will produce a nullptr reference
jglRenderModel( *reinterpret_cast<jmlGL::jglModel*>( nullptr ) );

This code is always invalid.


And no, these are not only restrictions of the language, it will really
produce invalid machine code. The following example will behave
unexpected on many platforms:

struct A
{ int a;
};
struct B
{ int b;
};
struct C : public A, public B
{ int c;
};

C* cptr = NULL;
C& cref = *cptr; // invalid, but usually here nothing strange happens
B& bref = cref; // Now the nullptr turns into something not null.
assert(&bref == NULL); // Fail!

If a reference type conversion requires an adjustment of the offset, it
is, in contrast to pointer types, not checked for NULL before. This
implies also that the use of references instead of pointers that must
not be NULL might have a performance gain with polymorphic types,
because of the omitted NULL checks.


Marcel
 
B

Bo Persson

Jim said:
Hmm.. this is dereferencing a nullptr isn't it? So I guess it's
illegal. So I have to wrap the null reference around something just
to do what I can already do. *sigh*

Right!

We don't know of any way to create a "null reference" without first
invoking undefined behavior.

A rule of thumb is to make the parameter a pointer if you accept null
values. Reference parameters are for when there must always be a valid
object.


Bo Persson
 
G

Goran Pusic

I wound up creating a null reference on accident using polymorphism and
wondered if this snippet is legal code, as it compiles and works as I would
expect it to work.

void jglRenderModel( jglModel& model ) {
   if ( &model == nullptr ) {
      return;
   }

Well, that's horrible code right there. It deals with passing an "null
reference" in (in quotes, as there's no such thing as a "null
reference" in C++). You can't have an invalid reference without
another bug in your own code, so checking for it here is covering for
a bug elsewhere, which is just wrong.

I think you should either change your "model" param to a pointer,
either make sure that you only go into jglRenderModel with a valid
object.

Goran.
 
M

Martin B.

Jim said:
I wound up creating a null reference on accident using polymorphism
and wondered if this snippet is legal code, as it compiles and works
as I would expect it to work.

[...]


And no, these are not only restrictions of the language, it will really
produce invalid machine code. The following example will behave
unexpected on many platforms:

struct A
{ int a;
};
struct B
{ int b;
};
struct C : public A, public B
{ int c;
};

C* cptr = NULL;
C& cref = *cptr; // invalid, but usually here nothing strange happens
B& bref = cref; // Now the nullptr turns into something not null.
assert(&bref == NULL); // Fail!

If a reference type conversion requires an adjustment of the offset, it
is, in contrast to pointer types, not checked for NULL before. This
[...]

Who's checking when and what (part of the standard) mandates this behaviour?

cheers,
Martin
 
M

Marcel Müller

Martin said:
If a reference type conversion requires an adjustment of the offset, it
is, in contrast to pointer types, not checked for NULL before. This
[...]

Who's checking when and what (part of the standard) mandates this
behaviour?

The standard says absolutly nothing about that. But this is what is
actually happening in implementations. In fact, I only like to show that
NULL references are not just UB, but working as NULL pointers otherwise.
They definitely break code.


Marcel
 
B

Bart van Ingen Schenau

Jim said:
I wound up creating a null reference on accident using polymorphism
and wondered if this snippet is legal code, as it compiles and works
as I would expect it to work.
[...]
And no, these are not only restrictions of the language, it will really
produce invalid machine code. The following example will behave
unexpected on many platforms:
struct A
{ int a;
};
struct B
{ int b;
};
struct C : public A, public B
{ int c;
};
C* cptr = NULL;
C& cref = *cptr; // invalid, but usually here nothing strange happens
B& bref = cref; // Now the nullptr turns into something not null.
assert(&bref == NULL); // Fail!
If a reference type conversion requires an adjustment of the offset, it
is, in contrast to pointer types, not checked for NULL before. This
[...]

Who's checking when and what (part of the standard) mandates this behaviour?

As derived to base conversions are not forbidden for null pointers and
must yield a null pointer, this must work as expected:

B* bptr = cptr;
assert(bptr == NULL); // Pass

If the conversion from C* to B* requires a pointer offset, that must
be guarded to ensure that the result is still a nullpointer if the
source was a null pointer.
cheers,
Martin

Bart v Ingen Schenau
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,012
Latest member
RoxanneDzm

Latest Threads

Top