Pointers and reference issue - c++

I'm creating something similar to structure list. At the beginning of main I declare a null pointer. Then I call insert() function a couple of times, passing reference to that pointer, to add new elements.
However, something seems to be wrong. I can't display the list's element, std::cout just breaks the program, even though it compiler without a warning.
#include <iostream>
struct node {
node *p, *left, *right;
int key;
};
void insert(node *&root, const int key)
{
node newElement = {};
newElement.key = key;
node *y = NULL;
std::cout << root->key; // this line
while(root)
{
if(key == root->key) exit(EXIT_FAILURE);
y = root;
root = (key < root->key) ? root->left : root->right;
}
newElement.p = y;
if(!y) root = &newElement;
else if(key < y->key) y->left = &newElement;
else y->right = &newElement;
}
int main()
{
node *root = NULL;
insert(root, 5);
std::cout << root->key; // works perfectly if I delete cout in insert()
insert(root, 2);
std::cout << root->key; // program breaks before this line
return 0;
}
As you can see, I create new structure element in insert function and save it inside the root pointer. In the first call, while loop isn't even initiated so it works, and I'm able to display root's element in the main function.
But in the second call, while loop already works, and I get the problem I described.
There's something wrong with root->key syntax because it doesn't work even if I place this in the first call.
What's wrong, and what's the reason?
Also, I've always seen inserting new list's elements through pointers like this:
node newElement = new node();
newElement->key = 5;
root->next = newElement;
Is this code equal to:
node newElement = {};
newElement.key = 5;
root->next = &newElement;
? It would be a bit cleaner, and there wouldn't be need to delete memory.

The problem is because you are passing a pointer to a local variable out of a function. Dereferencing such pointers is undefined behavior. You should allocate newElement with new.
This code
node newElement = {};
creates a local variable newElement. Once the function is over, the scope of newElement ends, and its memory gets destroyed. However, you are passing the pointer to that destroyed memory to outside the function. All references to that memory become invalid as soon as the function exits.
This code, on the other hand
node *newElement = new node(); // Don't forget the asterisk
allocates an object on free store. Such objects remain available until you delete them explicitly. That's why you can use them after the function creating them has exited. Of course since newElement is a pointer, you need to use -> to access its members.

The key thing you need to learn here is the difference between stack allocated objects and heap allocated objects. In your insert function your node newElement = {} is stack allocated, which means that its life time is determined by the enclosing scope. In this case that means that when the function exits your object is destroyed. That's not what you want. You want the root of your tree to stored in your node *root pointer. To do that you need to allocate memory from the heap. In C++ that is normally done with the new operator. That allows you to pass the pointer from one function to another without having its life time determined by the scope that it's in. This also means you need to be careful about managing the life time of heap allocated objects.

Well you have got one problem with your Also comment. The second may be cleaner but it is wrong. You have to new memory and delete it. Otherwise you end up with pointers to objects which no longer exist. That's exactly the problem that new solves.
Another problem
void insert(node *&root, const int key)
{
node newElement = {};
newElement.key = key;
node *y = NULL;
std::cout << root->key; // this line
On the first insert root is still NULL, so this code will crash the program.

It's already been explained that you would have to allocate objects dynamically (with new), however doing so is fraught with perils (memory leaks).
There are two (simple) solutions:
Have an ownership scheme.
Use an arena to put your nodes, and keep references to them.
1 Ownership scheme
In C and C++, there are two forms of obtaining memory where to store an object: automatic storage and dynamic storage. Automatic is what you use when you declare a variable within your function, for example, however such objects only live for the duration of the function (and thus you have issues when using them afterward because the memory is probably overwritten by something else). Therefore you often must use dynamic memory allocation.
The issue with dynamic memory allocation is that you have to explicitly give it back to the system, lest it leaks. In C this is pretty difficult and requires rigor. In C++ though it's made easier by the use of smart pointers. So let's use those!
struct Node {
Node(Node* p, int k): parent(p), key(k) {}
Node* parent;
std::unique_ptr<Node> left, right;
int key;
};
// Note: I added a *constructor* to the type to initialize `parent` and `key`
// without proper initialization they would have some garbage value.
Note the different declaration of parent and left ? A parent owns its children (unique_ptr) whereas a child just refers to its parent.
void insert(std::unique_ptr<Node>& root, const int key)
{
if (root.get() == nullptr) {
root.reset(new Node{nullptr, key});
return;
}
Node* parent = root.get();
Node* y = nullptr;
while(parent)
{
if(key == parent->key) exit(EXIT_FAILURE);
y = parent;
parent = (key < parent->key) ? parent->left.get() : parent->right.get();
}
if (key < y->key) { y->left.reset(new Node{y, key}); }
else { y->right.reset(new Node{y, key}); }
}
In case you don't know what unique_ptr is, the get() it just contains an object allocated with new and the get() method returns a pointer to that object. You can also reset its content (in which case it properly disposes of the object it already contained, if any).
I would note I am not too sure about your algorithm, but hey, it's yours :)
2 Arena
If this dealing with memory got your head all mushy, that's pretty normal at first, and that's why sometimes arenas might be easier to use. The idea of using an arena is pretty general; instead of bothering with memory ownership on a piece by piece basis you use "something" to hold onto the memory and then only manipulate references (or pointers) to the pieces. You just have to keep in mind that those references/pointers are only ever alive as long as the arena is.
struct Node {
Node(): parent(nullptr), left(nullptr), right(nullptr), key(0) {}
Node* parent;
Node* left;
Node* right;
int key;
};
void insert(std::list<Node>& arena, Node *&root, const int key)
{
arena.push_back(Node{}); // add a new node
Node& newElement = arena.back(); // get a reference to it.
newElement.key = key;
Node *y = NULL;
while(root)
{
if(key == root->key) exit(EXIT_FAILURE);
y = root;
root = (key < root->key) ? root->left : root->right;
}
newElement.p = y;
if(!y) root = &newElement;
else if(key < y->key) y->left = &newElement;
else y->right = &newElement;
}
Just remember two things:
as soon as your arena dies, all your references/pointers are pointing into the ether, and bad things happen should you try to use them
if you ever only push things into the arena, it'll grow until it consumes all available memory and your program crashes; at some point you need cleanup!

Related

How can I delete the Error when creating pointers on C++? I this case I have to use raw pointers

I'm trying to make a linked list with a pointer to a template class called Node:
template <typename T>
class llnode
{
public:
T key;
llnode<T> *prev, *next;
llnode()
{
};
llnode(const T &k, llnode<T> *w = NULL, llnode<T> *y = NULL) : key(k), prev(w), next(y){};
~llnode()
{
delete this;
}
};
But, when I run the program this code in the main function
llnode<int> *node;
node->key = 6;
llnode<int> *node1;
node->key = 2;
I get the error message:
403 cygwin_exception::open_stackdumpfile: Dumping stack trace to "NAME OF MY EXE".exe.stackdump
How can I create more nodes without getting the error?
It happens when I have 2 nodes created, but when I have 1 it does it right.
When you use them in main your pointers are not initializated. This ends in Undefined Behavior.
Do this:
llnode<int> *node = new llnode<int>;
node->key = 6;
llnode<int> *node1 = new llnode<int>;
node->key = 2;
Also note that calling delete this; in the destructor causes an infinite loop (More info here). Remove the destructor and free the space manually or better use a Smart Pointers or RAII approach.
First, for
llnode<int> *node;
node->key = 6;
llnode<int> *node1;
node->key = 2;
your problem is that node is an uninitialized pointer. You should always initialize your pointers (or better, use smart pointers like unique_ptr). Try:
std::unique_ptr<llnode<int>> node = std::make_unique<llnode<int>>();
node->key = 6;
std::unique_ptr<llnode<int>> node1 = std::make_unique<llnode<int>>();
node->key = 2;
or better:
auto node = std::make_unique<llnode<int>>(6);
auto node1 = std::make_unique<llnode<int>>(2);
In general, this is very C-like C++. Raw pointers are hard to use correctly, particularly when it comes to exception safety. For that reason, I make an effort to never write new or delete ever. (There are places, but really, you want to avoid them.)
You can use std::unique_ptr to do cleanup (and initialization) for you. You can also default raw pointers to nullptr.
In C++11 and beyond, don't use NULL, use nullptr, it's safer.
Consider something like this:
#include <memory>
template <typename T>
class llnode
{
public:
T key;
llnode<T>* prev = nullptr; // Raw pointer back
std::unique_ptr<llnode<T>> next; // List owns it tail.
llnode(const T &k = {},
llnode<T> *w = nullptr,
std::unique_ptr<llnode<T>> y = nullptr)
: key(k), prev(w), next(std::move(y)) {}
};
When this node is deleted, the node pointed to by next (if next != nullptr) will also be deleted for you.
Often a doubly-linked linked list will have a separate type that hides the nodes from the user, maintaining access to the front and back. Then you can provide standard operations such as list<T>.push_back(const T&).

C++ object pointer scope

I started writing a binary tree and then came up with this example and I'm not sure what's going on. So here's the code:
#include<iostream>
using namespace std;
struct Node
{
Node *left, *right;
int key;
Node()
{
left = NULL;
right = NULL;
key = 0;
}
Node(int key)
{
left = NULL;
right = NULL;
key = key;
}
};
struct Tree
{
Node* root;
void Add(int k)
{
Node* t;
t->key = k;
root->left = t;
}
Tree(int key)
{
this->root = new Node(key);
}
};
int main()
{
Tree* tree = new Tree(5);
tree->Add(4);
cout<<tree->root->left->key;
return 0;
}
Add function Add in Tree is whats confuses me. So, there is a pointer to Node object, but new keyword is not used and it appears to me that anyway there is memory allocated in the heap because I can reach the object. Shouldn't go out of scope and be destroyed? And why I can reach that object and print out its key?
Probably that memory belongs to your program and nothing bad seems to happen because you are using so little memory. If you use more memory, some object will own that unallocated space and expect it to remain unmodified. Then this code will start giving you problems.
You are "dereferencing an uninitilized pointer". There are questions relating to this here and here, for instance. Your compiler may blow up if you do this, or it may not: the behaviour is undefined. Anything might happen, including the appearance that things are working.
Use new, like you should.
This line …
Node* t;
… is like:
Node* t = random_address;
It means that the next line …
t->key = k;
… is able to corrupt interesting memory locations.
The code is invalid. In this function
void Add(int k)
{
Node* t;
t->key = k;
root->left = t;
}
local variable t is not initialized and has indeterminate value. So the execution of the statement
t->key = k;
results in undefined behaviour.
You correctly pointed to that there must be used operator new. For example
Node* t = new Node( k );
Nevertheless even in this case the function is invalid because it has to check whether the new key is less of greater than the key of root. Depending on the condition there should be either
root->left = t;
or
root->right = t;

Is Typecasting a normal pointer to a unique_ptr a bad practice?

I implemented a singly linked list using unique_ptr with mix of normal pointers.
I have this code:
template<typename B>
void linkedlist<B>::addNode(B x){
node * n = new node; //initialize new node
n->x = x;
n->next = nullptr; //smart pointer
if(head == nullptr){ //if the list is empty
head = (unique_ptr<node>)n; //cast the normal pointer to a unique pointer
}else{ //if there is an existing link
current = head.get(); //get the address that is being
//pointed by the unique_ptr head
while(current->next != nullptr) //loop until the end then stop
current = (current->next).get();
current->next = (unique_ptr<node>) n; //connect the new node to the last node
}
}
I heard that it's a bad practice, if so then can someone tell me why? Suggestions and tips for proper practices will also be appreciated.
While the cast syntax is slightly strange, it's exactly equivalent to the more conventional
unique_ptr<node>(n)
and so isn't itself bad practice. What is bad practice is to have the raw pointer hanging around at all, with a danger that it might leak if there is a code path that doesn't either delete it or transfer it to a smart pointer.
You should start with
unique_ptr<node> n(new node);
and transfer ownership by moving from it
head = std::move(n);
In your case it may not be an issue but casting existing raw pointers to unique_ptrs is a bit of a bad practice mainly due to the semantics involved. Unique_ptr will run a deleter when goes out of scope.
Consider the following
int ptr_method(int * i) {
auto a = (unique_ptr<int>)i;
return *a.get();
}
int main() {
int i = 10;
ptr_method(&i);
}
What happens to i when ptr_method returns ?

Unique Pointer attempting to reference a deleted function

Hello I am trying to use pointers and learning the basics on unique pointers in C++. Below is my code I have commented the line of code in main function. to debug the problem However, I am unable to do so. What am I missing ? Is my move() in the insertNode() incorrect ? The error I get is below the code :
#include<memory>
#include<iostream>
struct node{
int data;
std::unique_ptr<node> next;
};
void print(std::unique_ptr<node>head){
while (head)
std::cout << head->data<<std::endl;
}
std::unique_ptr<node> insertNode(std::unique_ptr<node>head, int value){
node newNode;
newNode.data = value;
//head is empty
if (!head){
return std::make_unique<node>(newNode);
}
else{
//head points to an existing list
newNode.next = move(head->next);
return std::make_unique<node>(newNode);
}
}
auto main() -> int
{
//std::unique_ptr<node>head;
//for (int i = 1; i < 10; i++){
// //head = insertNode(head, i);
//}
}
ERROR
std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
Aside from other small problems, the main issue is this line:
return std::make_unique<node>(newNode);
You are trying to construct a unique pointer to a new node, passing newNode to the copy constructor of node. However, the copy constructor of node is deleted, since node contains a non-copyable type (i.e. std::unique_ptr<node>).
You should pass a std::move(newNode) instead, but this is problematic since you create the node on the stack and it will be destroyed at the exit from the function.
Using a std::unique_ptr here is a bad idea in my opinion, since, for example, to print the list (or insert into the list), you need to std::move the head (so you lose it) and so on. I think you're much better off with a std::shared_ptr.
I was having the same problem and indeed using a shared_ptr works.
Using the smart pointer as an argument in the function copies the pointer (not the data it points to), and this causes the unique_ptr to reset and delete the data it was previously pointing at- hence we get that "attempting to reference a deleted function" error. If you use a shared_ptr this will simply increment the reference count and de-increment it once you are out of the scope of that function.
The comments in the answers above suggest that using a shared_ptr is baseless. These answers were written before the C++17 standard and it is my understanding that we should be using the most updated versions of the language, hence the shared_ptr is appropriate here.
I don't know why we have to expose node type to user in any case. Whole thingamajig of C++ is to write more code in order to write less code later, as one of my tutors said.
We would like to encapsulate everything and leave no head or tail (pun intended) of node to user. Very simplistic interface would look like:
struct list
{
private:
struct node {
int data;
std::unique_ptr<node> next;
node(int data) : data{data}, next{nullptr} {}
};
std::unique_ptr<node> head;
public:
list() : head{nullptr} {};
void push(int data);
int pop();
~list(); // do we need this?
};
The implementation does something what Ben Voigt mentioned:
void list::push(int data)
{
auto temp{std::make_unique<node>(data)};
if(head)
{
temp->next = std::move(head);
head = std::move(temp);
} else
{
head = std::move(temp);
}
}
int list::pop()
{
if(head == nullptr) {
return 0; /* Return some default. */
/* Or do unthinkable things to user. Throw things at him or throw exception. */
}
auto temp = std::move(head);
head = std::move(temp->next);
return temp->data;
}
We actually need a destructor which would NOT be recursive if list will be really large. Our stack may explode because node's destructor would call unique_ptr's destructor then would call managed node's destructor, which would call unique_ptr's destructor... ad nauseatum.
void list::clear() { while(head) head = std::move(head->next); }
list::~list() { clear(); }
After that default destructor would ping unique_ptr destructor only once for head, no recursive iterations.
If we want to iterate through list without popping node, we'd use get() within some method designed to address that task.
Node *head = list.head.get();
/* ... */
head = head->next.get();
get() return raw pointer without breaking management.
How about this example, in addition to the sample code, he also mentioned some principles:
when you need to "assign" -- use std::move and when you need to just traverse, use get()

new dynamic allocation vs normal allocation

what's the difference between these two methods?
Method(CustomClass t)
{
CustomClass *temp = &t;
}
called like this
Method(CustomClass(1,2,3));
and
Method(CustomClass* t)
{
CustomClass *temp = t;
}
called like this
Method(new CustomClass(1,2,3));
i haven't coded in c++ for a few years now and am having some trouble remembering. I'm coming from c# where every class need to be dynamically allocated with 'new'. The thing is that i don't undertand the difference between alocating an object dynamically with 'new' and calling it normally. How does temp differ in the 2 examples?
More specific example: I was creating a linked list and for my list i had this method:
void List::AddNew(TestClass node)
{
if (!first)
{
first = &node;
}
else
{
bool setFirst = false;
if (!last)
setFirst = true;
TestClass *temp;
temp = last;
last = &node;
if (temp)
temp->next = last;
if (setFirst)
first->next = last;
}
}
where first and last are TestClass *; the list wasn't initialized correctly (first and last pointed to the same value) and i had no idea why, so i changed the method to this:
void List::AddNew(TestClass* node)
{
if (!first)
{
first = node;
}
else
{
bool setFirst = false;
if (!last)
setFirst = true;
TestClass *temp;
temp = last;
last = node;
if (temp)
temp->next = last;
if (setFirst)
first->next = last;
}
}
and now it works. I'm missing a basic principle for pointers and i can't seem to guess that it is.
Here is TestClass also:
class TestClass
{
public:
int x, y;
TestClass *next;
TestClass *prev;
TestClass();
TestClass(int,int);
~TestClass();
};
what's the difference between these two methods?
One of them is using stack (automatic) allocation, while the other is using heap (dynamic) allocation.
Method(CustomClass(1,2,3)); // stack based
Method(new CustomClass(1,2,3)); // heap based
If you're going to use new you need to make sure you delete that reference also. Otherwise, you'll have a memory leak.
yes, i know this but what's the real defference between the
allocations and when should i use one or the other?
Object lifetime. If you put something on the stack, you will only be able to use it within a particular function, and any functions below it will need it passed as a parameter. If you put it on the heap, you can return a reference to it and use it wherever you want. You can't return a reference / address to a stack variable since it's life ends when the function returns.
I think you're most confused about when to use dynamic-allocation vs when to use stack-allocation. The only thing to know is that you should use stack-based allocation when there is no need for dynamic-based allocation. When is dynamic- (or heap) allocation needed you ask? Well, normally you would use it when you need an object to exist beyond the scope in which it was created or when the contents of that dynamically-allocated object rely on a strictly runtime mechanism (like the addition of elements to a vector (the size may not be known at compile-time)). Also, this...
T* t = &t;
Is not heap-allocation. This is simply a pointer with automatic-storage duration (on the stack) pointing to another object on the stack (if t is itself stack-based). Allocation on the heap happens only when new is used.
CustomClass *temp;
temp is only a pointer. It points to NULL(ok, actually it can point everywhere, but you should set it to NULL if no object exists) or to a already existing class.
CustomClass tmp;
Creates a object.
Method(CustomClass* t):
Demands for a already existing Object (t = pointer to existing object).
CustomClass *temp = t;
Assigns the pointer to a new local pointer.
Method(CustomClass t):
Should create a copy of the class you pass (not sure...)
CustomClass *temp = &t;
& = Adress-Operator. Retrieves address of t and saves it to the local pointer temp.
mfg