44

In the C++11 standard, I don't understand the reason why taking the address of nullptr is disallowed whereas one is allowed to take the address of their own std::nullptr_t instances. Aside from the fact that nullptr is a reserved keyword, is there any designated reasoning for this decision?

Simply because it amuses me, I attempted to circumnavigate this restriction with the following function:

decltype(nullptr)* func(const decltype(nullptr) &nref) noexcept
{
    return const_cast<decltype(nullptr)*>(reinterpret_cast<const decltype(nullptr)*>(&nref));
}

I had to use reinterpret_cast on the parameter because without it I was getting the hysterical error:

error: invalid conversion from 'std::nullptr_t*' to 'std::nullptr_t*' [-fpermissive]

When I call this function by passing nullptr directly I get a different address each time. Is nullptr dynamically assigned an address just-in-time for comparisons and such? Or (probably more likely) perhaps is the compiler forcing a temporary copy of the underlying object?

Of course none of this is vital information, I just find it interesting why this particular restriction was implemented (and subsequently why I am seeing the behavior I am).

Vishnu CS
  • 748
  • 1
  • 10
  • 24
monkey0506
  • 2,489
  • 1
  • 21
  • 27
  • 24
    `nullptr` is a prvalue. You can't take the address of those. +1 for the error message, though. – chris Jan 07 '13 at 04:03

4 Answers4

84

It's the same as not being able to take the address of 5 even though you can take the address of an int after giving it the value 5. It doesn't matter that there's no alternative value for a nullptr_t to have.

Values don't have addresses; objects do.

A temporary object is generated when you pass such a value to a const & parameter, or otherwise bind a value to a const reference, such as by static_cast< T const & >( … ) or declaring a named reference T const & foo = …;. The address you're seeing is that of the temporary.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • 2
    Thanks! I was actually digging around a bit more and I stumbled across [this answer to a related question](http://stackoverflow.com/questions/6664115/is-nullptr-not-a-special-keyword-and-an-object-of-stdnullptr-t/6664283#6664283). It then dawned on me that **nullptr** is intended as a null pointer literal, yes? It makes sense that you wouldn't be able to take the address of a literal. :) – monkey0506 Jan 07 '13 at 04:10
  • 20
    Yes, `nullptr` is a keyword which represents a literal. Just like `true` and `false` (and you can't do `&true` either). – aschepler Jan 07 '13 at 04:11
  • Yup! :D I think that when I was reading "null pointer _constant_" I was reading it simply as "_logical_ constant" rather than "_literal_ constant". – monkey0506 Jan 07 '13 at 04:18
  • Congrats on your new top answer, by the way :) – chris Jan 07 '13 at 15:38
28

If you're after a standard answer, § 18.2/9 puts your observations pretty bluntly:

Although nullptr’s address cannot be taken, the address of another nullptr_t object that is an lvalue can be taken.

Alternatively, § 2.14.7 says this about nullptr:

The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t.

So what is a prvalue? § 3.10/1 answers that:

A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. [ Example: The result of calling a function whose return type is not a reference is a prvalue. The value of a literal such as 12, 7.3e5, or true is also a prvalue. — end example ]

Hopefully, trying to take the address of any of those things in the example will make more sense as to why you can't take the address of nullptr. It's part of those examples!

chris
  • 60,560
  • 13
  • 143
  • 205
  • 2
    Ah, I was unaware what a prvalue was until now, +1. – Seth Carnegie Jan 07 '13 at 05:05
  • 1
    @SethCarnegie, I like their definition. Sometimes when I go through the standard to fully define something, it greatly reminds me of recursion. – chris Jan 07 '13 at 05:15
  • @SethCarnegie, I forgot about this, but if it's not just prvalues, have a look at [this question](http://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues) for the others like it. – chris Jan 11 '13 at 01:35
  • @chris oh awesome, I hadn't seen that, favourited. As an aside, I find it interesting that the top answer (for this question) has ~30 more upvotes than yours. I'm not sure why that is. – Seth Carnegie Jan 11 '13 at 02:10
  • @SethCarnegie, I was a bit later in answering, after quite a few votes had been cast, but the thing that really makes you go "ohhhh" in this answer is the last quotation, which, if you'll notice, the top answer has done, just more plainly and off-the-bat. I meant this as a proof of it that one could follow to see per the standard why this is invalid. – chris Jan 11 '13 at 02:22
10

nullptr is a (literal) constant, and these don't have a memory address, like any other literal constant in your code. It's similar to 0, but of the special std::nullptr_t type instead of void* to avoid problems with overloading (pointers vs. integers).

But if you define your own variable with the value nullptr, it has a memory address, so you can take its address.

The same holds for any other literal constant (which in C++ fall under the category prvalue) of any other type, since literal constants aren't stored in your program (only as parts of expressions where they occur), that's why it doesn't make any sense to talk about addresses. However, constant variables do have addresses, to point out the difference.

leemes
  • 44,967
  • 21
  • 135
  • 183
4

Both true and false are keywords and as literals they have a type ( bool ). nullptr is a pointer literal of type std::nullptr_t, and it's a prvalue (you cannot take the address of it using &), also nullptr is prvalue so you can't take its address,literal constants are not stored in your program.

It doesn't make sense to have address.

Ahmed Kato
  • 1,697
  • 4
  • 29
  • 53