43

According to the draft of the standard N4713 (7.11/1):

A null pointer constant is an integer literal (5.13.2) with value zero or a prvalue of type std::nullptr_t.

and 21.2.3/2:

The macro NULL is an implementation-defined null pointer constant.

follow that NULL can be defined as nullptr. Same is mentioned on cppreference:

#define NULL 0
//since C++11
#define NULL nullptr

At the same time "Additive operators" clause says (8.5.6/7):

If the value 0 is added to or subtracted from a null pointer value, the result is a null pointer value. If two null pointer values are subtracted, the result compares equal to the value 0 converted to the type std::ptrdiff_t.

Hence the following code should be valid:

0 + nullptr; 
nullptr - nullptr; 

but because of the lack of +/- operators for std::nullptr_t the code is invalid.

Is there something that I didn't take into account or NULL macro can't be actually defined as nullptr?

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
αλεχολυτ
  • 4,792
  • 1
  • 35
  • 71

4 Answers4

50

While nullptr is a null pointer constant, it is not a null pointer value. The latter is a value of some pointer type, which std::nullptr_t is not.

Reference:

A null pointer constant is an integer literal (5.13.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. [...]

7.11/1 in N4659, emphasize mine

So NULL can indeed be nullptr without providing the arithmetic operators.

Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
  • @Cheersandhth.-Alf It's a value alright, but the standard explicitly speaks of null pointer values as values of pointers. `nullptr` is not a pointer. – Baum mit Augen Feb 21 '18 at 10:58
  • 6
    @Cheersandhth.-Alf - No, he deserves an up-vote because the standard text treats *null pointer value* as a term, and not just *value*. And if you want to dredge up past encounters, don't you go then blaming others for getting personal. – StoryTeller - Unslander Monica Feb 21 '18 at 11:00
  • Any constant is a value. There just isn't any requirement that `nullptr` should support addition. However, literal `0` does support addition, and the standard describes the result of adding compile time 0 to `0`. – Cheers and hth. - Alf Feb 21 '18 at 11:02
  • @Cheersandhth.-Alf If I'm wrong, could you please give me a better explanation than *"A constant is a value"*? A lot of things are values in C++, how that's relevant to the question whether `nullptr` is a null pointer value is not clear to me yet. – Baum mit Augen Feb 21 '18 at 11:03
  • @BaummitAugen - Perhaps [\[basic.compound\]/3](https://timsong-cpp.github.io/cppwp/n4659/basic.compound#3), to better drive that point home? – StoryTeller - Unslander Monica Feb 21 '18 at 11:05
  • @BaummitAugen: I think [S.M.'s answer](https://stackoverflow.com/a/48904174/464581) is good. Also my own in comments to question. – Cheers and hth. - Alf Feb 21 '18 at 11:05
  • 2
    @Cheersandhth.-Alf Sorry, but I fail to see how *"`nullptr` itself is not a pointer value nor pointer. Thus arithmetic operations are not applicable to `nullptr`"* is right if *"it is not a null pointer value"* is wrong. – Baum mit Augen Feb 21 '18 at 11:11
  • @StoryTeller Thanks for the link, but I think that is more relevant for proving that a pointer can have a null pointer value, not so much for defining what that actually is. – Baum mit Augen Feb 21 '18 at 11:12
  • 2
    @Cheersandhth.-Alf C++17 7.11/1 "A *null pointer constant* is an integer literal (5.13.2) with value zero or a prvalue of type `std::nullptr_t`. A null pointer constant can be converted to a pointer type; the result is the *null pointer value* of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a *null pointer conversion.*" This seems to pretty clearly indicate that `nullptr` (or any other prvalue of type `std::nullptr_t`) is *not* a "null pointer value." – Angew is no longer proud of SO Feb 21 '18 at 11:13
  • @Angew: Thanks, but that was already cited by the OP. It says a nullpointer is, among other things a prvalue of type `std::nullptr`. That it is a prvalue supports that it is a value. – Cheers and hth. - Alf Feb 21 '18 at 11:15
  • 2
    @Cheersandhth.-Alf Whether or not it's a value is out of the question, but where does it say it's a null pointer value? – Baum mit Augen Feb 21 '18 at 11:17
  • **+1** @BaummitAugen: I found a definition, C++17 §7.11/1, and by that definition you're right. Sorry. I think you should cite that. – Cheers and hth. - Alf Feb 21 '18 at 11:20
  • @Cheersandhth.-Alf That's exactly the paragraph I already do cite, unless something has changed there between N4659 and C++17. I haven't bought the latter, so if relevant, thanks for pointing out the difference. – Baum mit Augen Feb 21 '18 at 11:22
  • 3
    I need new eyes. Sorry for the confusion! – Cheers and hth. - Alf Feb 21 '18 at 11:23
9

nullptr is a null pointer literal, and although the result of converting nullptr to a pointer type is the null pointer value, nullptr itself isn't of a pointer type, but of type std::nullptr_t. The arithmetic works if you do convert the nullptr to a pointer type:

0 + (int*)nullptr; 
(int*)nullptr - (int*)nullptr;

Can the NULL macro actually be a nullptr?

Yes, because nullptr is a null pointer literal.

Note that prior to C++11, the all of the null pointer literals in C++ happened to also be integer literals, so this bad code: char c = NULL; used to work in practice. If NULL is defined as nullptr, that code no longer works.

eerorika
  • 232,697
  • 12
  • 197
  • 326
6

The keyword nullptr denotes the pointer literal. It is a prvalue of type std::nullptr_t. There exist implicit conversions from nullptr to null pointer value of any pointer type and any pointer to member type. nullptr itself is not a pointer value nor pointer. Thus arithmetic operations are not applicable to nullptr.

273K
  • 29,503
  • 10
  • 41
  • 64
  • so 8.5.6/7 does not apply to `nullptr` because it is not a null pointer value? (deleted this comment after reading Baums answer and repostet after reading the discussion below that answer ;) – 463035818_is_not_an_ai Feb 21 '18 at 11:08
  • If `nullptr` is of `std::nullptr_t` type, and not of a pointer type, how is it a pointer literal? You may want to think about rephrasing a bit to be more accurate. – StoryTeller - Unslander Monica Feb 21 '18 at 11:09
  • @user463035818 Yes, you are correct. 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`] - copied from here https://stackoverflow.com/questions/3601602/what-are-rvalues-lvalues-xvalues-glvalues-and-prvalues – 273K Feb 21 '18 at 11:10
  • @StoryTeller `NULL` is implementation-defined null pointer constant. `nullptr_t` is the type of the null pointer literal `nullptr`, like `char` is the type of char literal `'a'`, or `const char const *` is the type of the string literal `"abc"`. – 273K Feb 21 '18 at 11:15
  • I don't think you got what I was aiming for. Literals are **typed** values. Since `nullptr_t` is not a pointer type, `nullptr` can't be a pointer literal. – StoryTeller - Unslander Monica Feb 21 '18 at 11:17
  • @StoryTeller I don't think the standard could be clearer about this: *"The **pointer literal** is the keyword nullptr. It is a prvalue of type std​::​nullptr_­t. [ Note: std​::​nullptr_­t is a distinct type that **is neither a pointer type** nor ..."* Clearly not being a pointer type does not prevent `nullptr` from being a pointer literal. – eerorika Feb 21 '18 at 11:20
  • @user2079303 - Well, so much for consistency with other prvalue literals. It's not of a "pointer type", but it's a "pointer literal"!? WTF. – StoryTeller - Unslander Monica Feb 21 '18 at 11:24
6

For addition, either both operands shall have arithmetic or unscoped enumeration type, or one operand shall be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration type.

For subtraction, one of the following shall hold:
(2.1) both operands have arithmetic or unscoped enumeration type; or
(2.2) both operands are pointers to cv-qualified or cv-unqualified versions of the same completely-defined object type; or
(2.3) the left operand is a pointer to a completely-defined object type and the right operand has integral or unscoped enumeration type.

std::nullptr_t is none of those, hence std::nullptr cannot participate in additive operations.

Note that not even all pointer values can participate. For example, function pointer values and void pointer values cannot, even though either can be a null pointer value.

Community
  • 1
  • 1
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243