What is the difference between nullptr and nullptr_t in C++? - c++

Which one should I use? Any advantages if I use one over the other?

nullptr is the constant, nullptr_t is its type. Use each one in contexts where you need respectively a null pointer, or the type of a null pointer.

"... if I use one over the other?"
You can't (use one over the other) they're orthogonal by these means:
nullptr_t is the type used to represent a nullptr
nullptr is (1)effectively a constant of type nullptr_t that represents a specific compiler implementation defined value.
See the C++11 standards section:
2.14.7 Pointer literals
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 a pointer to member type; rather, a prvalue of this type is a null pointer constant and can be converted to a null pointer value or null member pointer value. See 4.10
and 4.11. — end note ]
1) Just like the this keyword nullptr stands for an rvalue rather than being of const type. Thus, decltype(nullptr) can be a non-const type. With Visual C++ 2015 and MinGW g++ 5.1 it is non-const.

In exactly the same way that true is a C++ keyword literal of type bool, nullptr is a C++ keyword literal of type std::nullptr_t.

nullptr is of type nullptr_t.

If you try this
cout << typeid(nullptr).name() << endl;
you will see that nullptr is of type std::nullptr_t.

nullptr is a pointer literal of type std::nullptr_t.
And moreover nullptr is also a keyword of the C++ the same way as boolean literals false and true.:)

From [lex.nullptr]:
Pointer Literals
pointer-literal:
nullptr
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 a pointer to member type; rather, a prvalue of this type is
a null pointer constant and can be converted to a null pointer value or null member pointer value. See 4.10
and 4.11. —end note ]
So use nullptr when you need a pointer literal, and std::nullptr_t in a context when you need to take that type. The latter, for instance, if you're making a function or constructor or something that can take a nullptr as an argument.

Related

Can the NULL macro actually be a nullptr?

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?
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.
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.
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.
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.

How is 0 distinguished from other integers when initializing nullptr_t?

As I understand, std::nullptr_t can be initialized from nullptr as well as from 0. But at the same time the third initialization below doesn't work, despite 5 has the same type as 0:
#include <memory>
int main()
{
std::nullptr_t null1=0;
std::nullptr_t null2=nullptr;
std::nullptr_t null3=5; // error: cannot convert ‘int’ to ‘std::nullptr_t’ in initialization
}
How does this work? I.e. how does the standard library distinguish 0 from 5 at compilation time, if these literals aren't template arguments?
Can one create a custom class which would similarly distinguish arguments of its constructor at compilation time, not using std::nullptr_t for this?
A nullptr_t can be only assigned the value nullptr or 0 which is implicitly converted.
According to N4296 (page.86):
4.10 Pointer conversions
A null pointer constant is an integer literal 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. [...] A null pointer constant of
integral type can be converted to a prvalue of type std::nullptr_t.
You can not create a similar type within C++ yourself.
std::nullptr_t is implemented as a built-in type and its distinct properties are enforced by the compiler.
EDIT: Fixed paragraph on built-in types. Thanks Yakk!
how does the standard library distinguish 0 from 5 at compilation time, if these literals aren't template arguments?
This has nothing to do with the standard library at all, nullptr_t is a built-in type known to the compiler, and obviously the compiler knows the difference between 5 and 0
Can one create a custom class which would similarly distinguish arguments of its constructor at compilation time, not using std::nullptr_t for this?
In general no.
You can write a type that can be initialized from 0 and not from 5 by making it take an argument of a pointer type, because 0 is a valid null pointer constant but 5 is not. But you couldn't write a type that can be constructed from 3 and not from 5, or anything else like that.
N3337 [conv.ptr]/1: A null pointer constant is an integral constant expression prvalue of integer type that evaluates to
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. Two null pointer values of the
same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is
a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion. A null pointer constant of integral type can be converted to a prvalue of type std::nullptr_t.
0 is a null pointer constant of integral type, so it can be converted to a prvalue of type std::nullptr_t. 5 is not a null pointer constant, so it can't be.

Check for null pointer in a truth-value context

Lets say I have a pointer
MyType *ptr;
When checking the validity of that pointer in a "truth-value context" by the old standards I would write something like this
if (ptr) { ... // 1
while (ptr) { ... // 2
The thing is that in such "truth value contexes" we expect for the implicit conversion of a pointer to a boolean value to take place, so we would be pretty much be comparing
if (NULL != ptr) { ...
while (NULL != ptr) { ...
Yet comparing against a macro for the integer 0 is deprecated and C++11 proposes comparing against nullptr.
When in a truth value context though like (1) or (2) above where we don't explicitly say
if (nullptr != ptr) { ...
while (nullptr != ptr) { ...
what is our pointer compared against ? It's conversion to a boolean ? Do we have to explicitly compare against nullptr ?
The condition (if it's an expression) of an if statement is contextually converted to bool:
[stmt.select]/4 about the condition in selection statements (if, switch):
The value of a condition that is an expression is the value of the
expression, contextually converted to bool for statements other than switch; if that conversion is ill-formed, the program is ill-formed.
Contextual conversion to bool is defined as follows in [conv]/3:
An expression e can be implicitly converted to a type T if and only if the declaration T t=e; is well-formed, for some invented temporary variable t. Certain language constructs require that an expression be
converted to a Boolean value. An expression e appearing in such a context is said to be contextually converted to bool and is well-formed if and only if the declaration bool t(e); is well-formed, for some invented temporary variable t.
Here's the description of a conversion to bool for fundamental types [conv.bool]/1:
A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a
prvalue of type bool. A zero value, null pointer value, or null member pointer value is converted to false;
any other value is converted to true. A prvalue of type std::nullptr_t can be converted to a prvalue of
type bool; the resulting value is false.
So when we test a pointer if(ptr), we compare ptr to the null pointer value of that type. What's a null pointer value? [conv.ptr]/1
A null pointer constant is an integral constant expression prvalue of integer type that evaluates to
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. Two null pointer values of the
same type shall compare equal.
This also describes what happens when we compare if(ptr != nullptr): The nullptr is converted to the type of ptr (see [expr.rel]/2), and yields the null pointer value of that type. Hence, the comparison is equivalent to if(ptr).
Let's say you have:
int* ip = foo();
if ( nullptr == ip )
{
}
It's as if you are saying:
int* ip = foo();
if ( (int*)0 == ip )
{
}
At that point, you are comparing two pointers of the same type.
This is what I found at cppreference.com
Explanation
The keyword nullptr denotes the null pointer literal. It is an unspecified 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. Similar conversions exist for any value of type std::nullptr_t as well as for the macro NULL, the null pointer constant.

What is the return value of shared_ptr<T>::get() after it is released?

After releasing a std::shared_ptr<T>, when I do ptr.get() is the return value NULL or nullptr? In order to compare, I used this:
std::shared_ptr<int> ptr(new int(44));
ptr.reset();
int *p = ptr.get();
if (p == nullptr)
{
cout << "nullptr";
}
if (p == NULL)
{
cout << "NULL";
}
Both seem to be the result.
In C++11, use nullptr.
It is true that they are both correct and equivalent in this case, since both are null pointer constants as specified by paragraph 4.10/1 (NULL is usually #defined to be 0):
A null pointer constant is an integral constant expression (5.19) prvalue of integer type that evaluates to
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.
However, nullptr is recognized by the type system as the pointer literal of type nullptr_t and as a special null pointer constant, so its semantics are clear both to you and to the compiler. NULL, on the other hand, is just a macro that is known to expand to zero.
2.14.7 Pointer literals [lex.nullptr]
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 a pointer to member type; rather, a prvalue
of this type is a null pointer constant and can be converted to a null
pointer value or null member pointer value.
Both are equivalent, but you should prefer to use nullptr.

Is nullptr not a special keyword and an object of std::nullptr_t? [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
What exactly is nullptr?
I first thought it's a keyword. My present gcc doesn't highlight nullptr in a different shade. To verify that, I wrote following:
void *&p = nullptr;
So I got some clue from the error that:
error: invalid initialization of non-const reference of type ‘void*&’
from an rvalue of type ‘std::nullptr_t’
If nullptr is an object then is it really a pointer equivalent of simple 0? In other word, suppose I write:
#define NULL nullptr
Is the above statement doesn't alter anything in my code ? Also, it would be interesting to know other use cases for std::nullptr_t type as such.
It is a keyword, the standard draft says (lex.nullptr):
The pointer literal is the keyword nullptr. It is a prvalue of type std::nullptr_t.
the nullptr is not yet a pointer, but it can be converted to a pointer type. This forbids your above assignment, which is an assignment to an unrelated reference type, in which case no conversion is possible (consider int& a = 1.f;!).
Doing #define NULL nullptr shouldn't alter the behaviour unless you did use NULL in a context such as int i = 4; if(NULL == i) {}, which won't work with nullptr because nullptr is can't be treated as an integer literal.
I don't think there are many other use-cases for std::nullptr_t, it's just a sentinel because nullptr needs a type.
nullptr is a keyword that represents null pointer constant. It is of type nullptr_t, which is implicitly convertible and comparable to any pointer type or pointer-to-member type.
Read these,
Null pointer constant (wiki)
nullptr -- a null pointer literal (Bjarne Stroustrup's FAQ)
nullptr is indeed a keyword and the standard demands a type std::nullptr_t to be equivalent to typedef decltype(nullptr) nullptr_t; to enable overloading based on nullptr.
nullptr will be a keyword in next C++ standard, now called C++0x.
It is needed to disambiguate between f(int) and f(T*), so it's not simply 0, but of nullptr_t.
I didn't know gcc can highlight code ;-)
nullptr is not an object just like 0 is not an integer object. The former is a prvalue (i.e. a kind of expression) of type std::nullptr_t and the latter is an integer literal (also a kind of expression and also a prvalue) of type int.
It is possible to initialize an object with such expressions:
void* p = nullptr;
int i = 0;
It is not possible to initialize an lvalue reference with such expressions because they are prvalues; an lvalue reference can only be initialized from an lvalue.
void*& p = nullptr; // Invalid
int& i = 0; // Invalid