How is "int* ptr = int()" value initialization not illegal? - c++

The following code (taken from here):
int* ptr = int();
compiles in Visual C++ and value-initializes the pointer.
How is that possible? I mean int() yields an object of type int and I can't assign an int to a pointer.
How is the code above not illegal?

int() is a constant expression with a value of 0, so it's a valid way of producing a null pointer constant. Ultimately, it's just a slightly different way of saying int *ptr = NULL;

Because int() yields 0, which is interchangeable with NULL. NULL itself is defined as 0, unlike C's NULL which is (void *) 0.
Note that this would be an error:
int* ptr = int(5);
and this will still work:
int* ptr = int(0);
0 is a special constant value and as such it can be treated as a pointer value. Constant expressions that yield 0, such as 1 - 1 are as well allowed as null-pointer constants.

The expression int() evaluates to a constant default-initialized integer, which is the value 0. That value is special: it is used to initialize a pointer to the NULL state.

From n3290 (C++03 uses similar text), 4.10 Pointer conversions [conv.ptr] paragraph 1 (the emphasis is mine):
1 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. Such a conversion is called a null pointer conversion. [...]
int() is such an integral constant expression prvalue of integer type that evaluates to zero (that's a mouthful!), and thus can be used to initialize a pointer type. As you can see, 0 is not the only integral expression that is special cased.

Well int isn't an object.
I beleive what's happening here is you're telling the int* to point to some memory address determined by int()
so if int() creates 0, int* will point to memory address 0

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.

Why can std::cout print the value of nullptr only if returned by a function?

According to this question Unable to print the value of nullptr on screen
I can't print the value of a nullptr since it's of type nullptr_t, and std::cout has no such overload.
But, if you look at this:
int* f()
{
return nullptr;
}
int main()
{
std::cout << f();
}
The output is:
00000000
In this question Why does std::cout output disappear completely after NULL is sent to it they talk about a different problem.
I just want to understand why the std::cout can't print nullptr, but it actually can when nullptr is instead returned by a function.
The reason for this is that nullptr is convertible to any pointer type (which is "printable"), but it is not itself a pointer.
Have a look at What exactly is nullptr?
Here is the meaning of nullptr from the CPP Standards [4.10]
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. Such a conversion is called a null pointer conversion.
Something the CPP Standards specifies, is that it isn't a std::nullptr_t value, it evaluates to zero or a prvalue of type std::nullptr_t.
In your case, it's pretty much is an (TYPE) pointer to some extent, so when you try to paste it out, it pastes out it's type's value (Where it points to, but by itself it won't). Your function returns an int*, and you give it a nullptr. So what you are basically doing is giving an int* a value. nullptr by itself won't have a value but
int* abc = nullptr;
will.

How to write C/C++ code correctly when null pointer is not all bits zero

As the comp.lang.c FAQ says, there are architectures where the null pointer is not all bits zero. So the question is what actually checks the following construction:
void* p = get_some_pointer();
if (!p)
return;
Am I comparing p with machine dependent null pointer or I'm comparing p with arithmetic zero?
Should I write
void* p = get_some_pointer();
if (NULL == p)
return;
instead to be ready for such architectures or is it just my paranoia?
According to the C spec:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant. 55) If a null
pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.
So 0 is a null pointer constant. And if we convert it to a pointer type we will get a null pointer that might be non-all-bits-zero for some architectures. Next let's see what the spec says about comparing pointers and a null pointer constant:
If one operand is a
pointer and the other is a null pointer constant, the null pointer
constant is converted to the type of the pointer.
Let's consider (p == 0): first 0 is converted to a null pointer, and then p is compared with a null pointer constant whose actual bit values are architecture-dependent.
Next, see what the spec says about the negation operator:
The result of the logical negation operator ! is 0 if the value of its
operand compares unequal to 0, 1 if the value of its operand compares
equal to 0. The result has type int. The expression !E is equivalent
to (0==E).
This means that (!p) is equivalent to (p == 0) which is, according to the spec, testing p against the machine-defined null pointer constant.
Thus, you may safely write if (!p) even on architectures where the null pointer constant is not all-bits-zero.
As for C++, a null pointer constant is defined as:
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.
Which is close to what we have for C, plus the nullptr syntax sugar. The behavior of operator == is defined by:
In addition, pointers to members can be compared, or a pointer to
member and a null pointer constant. Pointer to member conversions
(4.11) and qualification conversions (4.4) are performed to bring them
to a common type. If one operand is a null pointer constant, the
common type is the type of the other operand. Otherwise, the common
type is a pointer to member type similar (4.4) to the type of one of
the operands, with a cv-qualification signature (4.4) that is the
union of the cv-qualification signatures of the operand types. [ Note:
this implies that any pointer to member can be compared to a null
pointer constant. — end note ]
That leads to conversion of 0 to a pointer type (as for C). For the negation operator:
The operand of the logical negation operator ! is contextually
converted to bool (Clause 4); its value is true if the converted
operand is true and false otherwise. The type of the result is bool.
That means that result of !p depends on how conversion from pointer to bool is performed. The standard says:
A zero value, null pointer value, or null member pointer value is
converted to false;
So if (p==NULL) and if (!p) does the same things in C++ too.
It doesn't matter if null pointer is all-bits zero or not in the actual machine. Assuming p is a pointer:
if (!p)
is always a legal way to test if p is a null pointer, and it's always equivalent to:
if (p == NULL)
You may be interested in another C-FAQ article: This is strange. NULL is guaranteed to be 0, but the null pointer is not?
Above is true for both C and C++. Note that in C++(11), it's preferred to use nullptr for null pointer literal.
This answer applies to C.
Don't mix up NULL with null pointers. NULL is just a macro guaranteed to be a null pointer constant. A null pointer constant is guaranteed to be either 0 or (void*)0.
From C11 6.3.2.3:
An integer constant expression with the value 0, or such an expression
cast to type void *, is called a null pointer constant 66). If a null
pointer constant is converted to a pointer type, the resulting
pointer, called a null pointer, is guaranteed to compare unequal to a
pointer to any object or function.
66) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.
7.19:
The macros are
NULL
which expands to an implementation-defined null pointer constant;
Implementation-defined in the case of NULL, is either 0 or (void*)0. NULL cannot be anything else.
However, when a null pointer constant is assigned to a pointer, you get a null pointer, which may not have the value zero, even though it compares equal to a null pointer constant. The code if (!p) has nothing to do with the NULL macro, you are comparing a null pointer against the arithmetic value zero.
So in theory, code like int* p = NULL may result in a null pointer p which is different from zero.
Back in the day, STRATUS computers had null pointers as 1 in all languages.
This caused issues for C, so their C compiler would allow pointer comparison of 0 and 1 to return true
This would allow:
void * ptr=some_func();
if (!ptr)
{
return;
}
To return on a null ptr even though you could see that ptr had a value of 1 in the debugger
if ((void *)0 == (void *)1)
{
printf("Welcome to STRATUS\n");
}
Would in fact print "Welcome to STRATUS"
If your compiler is any good there are two things (and only two things) to watch out for.
1: Static default initialized (that is, not assigned) pointers won't have NULL in them.
2: memset() on a struct or array or by extension calloc() won't set pointers to NULL.

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.