user14754470
user14754470

Reputation:

C++ can a reference of pointer take null?

Given the following code:

template<class S, class T>
class node {
public:
    S key;
    T value;
    node<S, T> *right_node, *left_node, *parent_node, *nearest_right_node, *nearest_left_node;
    int height;

public:
    template<typename, typename> friend
    class avl_tree;

    node() = default;

    node(const S *key, const T *value, node<S, T> *right_node = nullptr, node<S, T> *left_node = nullptr,
         node<S, T> *parent_node = nullptr, node<S, T> *nearest_right_node = nullptr,
         node<S, T> *nearest_left_node = nullptr) : key(*key),
                                                    value(*value),
                                                    right_node(right_node),
                                                    left_node(left_node),
                                                    parent_node(parent_node),
                                                    nearest_right_node(nearest_right_node),
                                                    nearest_left_node(nearest_left_node),
                                                    height(0) {
    }

    ~node() = default;
};

Can I replace the pointers in the c'tor for value and key with references and still able to give key and value a value of nullptr? (for example if S is int*)?

Update:

int* x;

    void update_x(int &new_x)
    {
        x=new_x;
    }

can I call update_x(null_ptr)

Upvotes: 1

Views: 83

Answers (2)

Remy Lebeau
Remy Lebeau

Reputation: 598319

Your node class has members S key and T value, and constructor parameters const S *key and const T *value which initialize the members using key(*key) and value(*value), respectively, which will copy the input values into the members.

If a nullptr is passed in to either parameter, the code has undefined behavior when dereferencing the nullptr.

There is no reason for the parameters to be pointers at all. They should be passed in either by value:

template<class S, class T>
class node {
public:
    S key;
    T value;
    ...

public:
    ...

    node(S key, T value, ...) : key(key), value(value), ... { }
    // or: node(S key, T value, ...) : key(std::move(key)), value(std::move(value)), ... { }

    ...
};

Or by const reference:

template<class S, class T>
class node {
public:
    S key;
    T value;
    ...

public:
    ...

    node(const S& key, const T& value, ...) : key(key), value(value), ... { }

    ...
};

Or by rvalue reference:

template<class S, class T>
class node {
public:
    S key;
    T value;
    ...

public:
    ...

    node(S&& key, T&& value, ...) : key(std::move(key)), value(std::move(value)), ... { }

    ...
};

If S or T are defined as pointer types, then a nullptr can be passed in as the value to be assigned to the key/value members, eg:

node<int, type*> *n = new node<int, type*>(1, nullptr);
type t;
node<int, type*> *n = new node<int, type*>(1, &t);

But if S and T are not pointer types, they should not be passed in as pointers:

type t;
node<int, type> *n = new node<int, type>(1, t);
type t;
node<int, type> *n = new node<int, type>(1, std::move(t));
node<int, type> *n = new node<int, type>(1, type{});

Upvotes: 2

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 123450

The issue in your code boils down to:

void foo(int* x) {
   int y = *x;
}

Passing a nullptr to foo will cause undefined behavior because you shall not dereference a nullptr.

Using a reference is possible but will not change that fact:

void bar(int*& x) {
    int y = *x;
}

This is passing the pointer by reference.

int a;
int* p = &a;
bar(p);

Now x in bar is a reference to the pointer to a. However, you cannot pass a nullpointer to bar, because bar is dereferencing the pointer. Some malicious code could do this:

int* p = nullptr;
bar(p);           // DO NOT DO THIS !!!

And then int y = *x; will invoke undefined behavior.

If the function expect to always get a valid object it should take it by reference:

void foo_bar(int& x) {
    int y = x;   // no danger, all fine
}

References cannot refer to nothing. They must be initialzed:

int& x; // ERROR !
int y;
int& z = y;  // OK, z refers to y

Pointers on the other hand not always point to a valid pointee:

int* p;       // not initialized, no (big) problem
p = nullptr;  // still not pointing to an int
int q;
p = &q;       // now p points to an int

References cannot refer to nothing, thats why when "nothing" is not a valid parameter you should prefer references over pointers. In your case you always require *value to be valid, hence value always must point to a S and you should use a reference instead to avoid the above mentioned problem.


Concerning your update:

int* x;

    void update_x(int &new_x)
    {
        x=new_x;
    }

can I call update_x(null_ptr)

No. You cannot. nullptr is not an int. A reference to an int always references an int.

Upvotes: 1

Related Questions