I'm aware that raw pointers (or more accurately new
and delete
) in modern C++ must be avoided unless really needed. I believe when it comes to graph implementation, pointers are pretty useful. I'd be happy to hear comments on this though.
I'm playing around with Binary Search Trees and writing insert
functions. I implemented using two different but similar methods, one using pointer and the other one using reference to pointer. Clearly I would like to change the the pointer itself (ref to ptr). Wondering if any of them has advantages or either should not be used and must be written using const reference or smart pointer (modern way).
Node *insert_ptr(Node *root, int data)
{
if (root == NULL)
return create(data);
else if (data < root->data)
root->left = insert(root->left, data);
else
root->right = insert(root->right, data);
return root;
}
void insert_ref_to_ptr(Node *&root, int data)
{
if (root == NULL)
root = create(data);
else if (data < root->data)
insert(root->left, data);
else
insert(root->right, data);
}
I'm providing the rest of code below if you want to get a run. You may want to use 1 3 6 8 10 14 13 4 7
as input
struct Node
{
int data;
Node *left;
Node *right;
};
void display(Node *root)
{
if (root != NULL)
{
display(root->left);
cout << root->data << " ";
display(root->right);
}
}
Node *create(int data)
{
Node *node = new Node();
node->data = data;
node->left = node->right = NULL;
return node;
}
int main()
{
Node *root = NULL;
vector<int> nodes;
string line;
int value;
getline(cin, line);
stringstream split(line);
while (split >> value)
nodes.push_back(value);
/*
root = insert_ptr(root, nodes[0]);
for (int i = 1; i < nodes.size(); i++)
insert_ptr(root, nodes[i]);
*/
for (int i = 0; i < nodes.size(); i++)
insert_ref_to_ptr(root, nodes[i]);
display(root);
return 0;
}
References are usually preferred over pointers whenever you don't need “reseating”. This usually means that references are most useful in a class's public interface. References typically appear on the skin of an object, and pointers on the inside.
It is best to avoid using pointers in C++ as much as possible. The use of pointers can lead to confusion of ownership which can directly or indirectly lead to memory leaks.
References are used to refer an existing variable in another name whereas pointers are used to store address of variable. References cannot have a null value assigned but pointer can. A reference variable can be referenced by pass by value whereas a pointer can be referenced but pass by reference.
References are Safer and Easier to Use References don't have to be dereferenced like pointers and can be used like normal variables (as an alias for some other variable). It is necessary to pass objects as a reference in a copy constructor.
that pointers in modern C++ must be avoided unless really needed
that's wrong.
new
and delete
should be avoided and you should use unique and shared pointers instead.
But you will still pass an object by reference or raw pointer if you don't transfer ownership.
Your Node
has an ownership relation so it should be:
struct Node
{
int data;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
};
or
struct Node
{
int data;
std::shared_ptr<Node> left;
std::shared_ptr<Node> right;
};
Your display
function does not need ownership, so you pass the node as pointer (or reference)
void display(Node *root)
{
if (root != nullptr)
{
display(root->left);
cout << root->data << " ";
display(root->right);
}
}
As you don't plan to change it I would go with const ref:
void display(const Node &root)
{
if(root.left != nullptr) {
display(*root.left);
}
cout << root.data << " ";
if(root.right != nullptr) {
display(*root.right);
}
}
You insert_ref_to_ptr
is a really bad construct, because it is not clear that it transferes any ownership and as is not clear that it calls create(data)
inside which create a Node using new
.
The create would look something like that:
std::unique_ptr<Node> create(int data)
{
auto node = std::make_unique<Node>();
node->data = data;
return std::move(node);
}
And the insert_ref_to_ptr
function something like that:
void insert_ref_to_ptr(std::unique_ptr<Node> &root, int data)
{
if (root == nullptr)
root = std::move(create(data));
else if (data < root->data)
insert(root->left, data);
else
insert(root->right, data);
}
I'm aware that pointers in modern C++ must be avoided unless really needed.
That is not true. What you probably heard is that you should avoid raw (naked) pointers if your requirements fit an standardized pattern/solution, like unique_ptr
.
Clearly I would like to change the the pointer itself (ref to ptr). Wondering if any of them has advantages or either should not be used and must be written using const reference (modern way).
If you want to have output parameters, you have quite some ways to do it:
struct
, std::tuple
or using structured bindings.There is not a single best way for all cases. Which one you use is up to you and how you are going to use the function. In some cases, it also depends on the coding style guidelines of the projects (e.g. in the case of reference vs. pointer). For instance:
f(a)
vs. f(&a)
).must be written using const reference (modern way).
By the way, note that you didn't write a const
reference, just a reference to Note *
. And it is not "modern C++": references were a part of the first C++ standard.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With