Osama Ahmad
Osama Ahmad

Reputation: 2096

What are the rules for a valid dereferencing of a null pointer?

#include <iostream>

struct X
{
    bool isNull() { return this == nullptr; }
    bool isNullConst() const { return this == nullptr; }
};

bool isNull(X& x) { return &x == nullptr; }
bool isNullConst(const X& x) { return &x == nullptr; }

// always false or exception.
bool isNullCopy(X x) { return &x == nullptr; } 

int main()
{
    X* x = nullptr;
    std::cout << x->isNull() << '\n';
    std::cout << (*x).isNull() << '\n';
    std::cout << isNull(*x) << '\n';
    // std::cout << isNull2(*x) << '\n'; // exception.
}

Here, I know that X::isNull() is equivalent to isNull(X&) and that X::isNullConst() is equivalent to isNullConst(const X&).

What I did not know is that it's normal to dereference a null pointer. I thought that any dereferencing for a null pointer would result in an exception.

After playing with pointers for a bit, I concluded that dereferencing a null pointer itself is not the problem, the problem is trying to read or write to the address pointed to by the null pointer.

And since the functions are in a well known location in memory, dereferencing a null pointer to a class and calling one of its functions will just result in calling the function with the null object as the first parameter.

That was new to me, but that's probably not the complete picture.

I thought at first that this was an OOP concept at first, thus it should work in java for example, but it didn't work here and caused an exception (which makes me think why it doesn't work in java?...):

class X
{
    boolean isNull() { return this == null; }
}

public class Main {

    public static void main(String[] args) {
        X x = null;
        System.out.println(x.isNull());
    }
}

So, clearly this is something related to C++ and not OOP in general.

What are all of the situations under which dereferencing a null pointer will be valid and won't cause exceptions?

Is there something else other than pointers of structs and classes that can be dereferenced successfully even if they're null pointers?

Also, why is calling a function of a null pointer without accessing its fields raises an exception in other languages like java?

One case where dereferencing a null pointer makes sense is in Red-Black trees for example. Null pointers are considered to be black.

#define RED true
#define BLACK false;

struct Node
{
    bool color;
    
    bool isRed()
    {
        return this != nullptr && this->color == RED;
    }
};

bool isRed(Node* node)
{
    return node != nullptr && node->color == RED;
}

Here, I believe it makes more sense to include the function in the Node class itself since it's related to it. It's not very convenient to include all of the logic related to the node inside it except for the one that checks for it being null.

Upvotes: 3

Views: 1391

Answers (3)

eerorika
eerorika

Reputation: 238351

What are the rules for a valid dereferencing of a null pointer [in C++]?

C++ standard is actually somewhat non-specific about whether indirecting through a null pointer is valid by itself or not. It is not disallowed explicitly. The standard used to use "dereferencing the null pointer" as an example of undefined behaviour, but this example has since been removed.

There is an active core language issue CWG-232 titled "Is indirection through a null pointer undefined behavior?" where this is discussed. It has a proposed change of wording to explicitly allow indirection through a null pointer, and even to allow "empty" references in the language. The issue was created 20 years ago, has last been updated 15 years ago, when the proposed wording was found insufficient.


Here are a few examples:

X* ptr = nullptr;

*ptr;

Above, the result of the indirection is discarded. This is a case where standard is not explicit about its validity one way or another. The proposed wording would have allowed this explicitly. This is also a fairly pointless operation.

X& x = *ptr;
X* ptr2 = &x; // ptr2 == nullptr?

Above, the result of indirection through null is bound to an lvalue. This is explicitly undefined behaviour now, but the proposed wording would have allowed this.

ptr->member_function();

Above, the result of indirection goes through lvalue-to-rvalue conversion. This has undefined behaviour regardless of what the function does, and would remain undefined in the proposed resolution of CWG-232. Same applies to all of your examples.

One consequence of this is that return this == nullptr; can be optimised to return false; because this can never be null in a well defined program.

Upvotes: 4

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122476

I thought that any dereferencing for a null pointer would result in an exception.

No. Dereferencing a null pointer is undefinded behavior in C++.

C++ is not Java. C++ does have exceptions, but they are only for exceptional casses, not used all over the place (as in Java). You are supposed to know that dereferencing a null pointer is not allowed, and a compiler assumes that it never happens in correct code. If it still happens your code is invalid.

Read about undefined behavior. It is essential to know about it when you want to do anything serious in C++.

What are the rules for a valid dereferencing of a null pointer?

The rule is: You shall not do it. When you do it your code is ill-formed no diagnostics required. This is a different way to say: Your code has undefined behavior. The compiler is not reuqired to issue an error or warning and when you ask a compiler to compile your wrong code the result can be anything.

Upvotes: 5

Quarra
Quarra

Reputation: 2695

Dereferencing a nullptr in C++ is an undefined behaviour, so technically anything can happen when you try to dereference a nullptr (and I mean: anything :)).

Upvotes: 1

Related Questions