Reputation:
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
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
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