Recursive data structure in c++ - c++

I'm implementing a recursive data structure in c++ using classes. I'm having some trouble implementing it particularly with the "this" pointer.
In one function, I need to modify the "this" pointer. However that is not allowed. How do I do it? I read somewhere that you will need to pass "this" pointer to that function to change it. However I'm not clear with that. Does that behave like python's "self"? An example would be great
EDIT:
void insert(int key)
{
if (head == NULL)
{
/* I need to insert in beginning of structure */
List* tmp;
tmp->key = key;
tmp->next = this;
this = tmp; /* This does not work */
}
}
Thank You!

You cannot modify the this pointer, given that it behaves as if declared T* const. What you could do is hold a pointer to your own type inside of the class, and modify that.
class foo
{
/* ... */
private:
foo* p; // this can be modified
};

You cannot modify this, period. You need to re-structure your program so that you don't need to do that.

The best way to insert the way you're trying to is to create a double linked list, not a single one (with only the next pointer). In other words, you should have a previous pointer that points to the previous node in the list to properly insert using the this pointer. Else you need to insert from the parent node of the this.
ie with a double linked list:
Node* tmp = new Node;
tmp->key = key;
this->previous->next = tmp;
tmp->previous = this->previous;
tmp->next = this;
this->previous = tmp;
Edit:
Don't forget that "this" is ""simply"" a memory address so what you want to change is what's contained in it.

Related

CPP - using * or & to return address

I am writing a code to make a linked list.
one of the function I wrote in order to make a linked list easier in the main function was[node is the name of a struct conatains a.data b.pointer name next) :
node& create_node(int value)
{
node newitem;
newitem.data=value;
newitem.next=NULL;
return (newitem);
};
When I write the function like this everything is ok but I want to write the function header as :
node * create_node(int value)
But when I write it that way and I write
return *newitem;
I get an error.
I wanted to ask why the VS shows me an error in the 2nd way and what is the difference between using * and & [I already read here about references but I don't understand why one should use it in functions as , from what I understood using references takes additional space and not contributing ] .
edit :thank you for help, when I posted this it was before I even ran a test on the main function only tried to avoid mistakes before compilation .
It took me some time but now I see the fundamental mistake I did .
If you want to return a pointer you should use a pointer:
node* create_node(int value)
{
node *newitem = new node;
newitem->data = value;
newitem->next = NULL;
return newitem;
};
Also please consider who'll delete the object then.
Your code returns a reference to a variable.
Unfortunately you return a reference to a local variable. This will fail, because the local variable will be destroyed uppont returning, but the caller will still try to reference it (that's UB) !
So if you want to return a reference, you shall make sure the object still exist:
node& create_node(int value) {
node* newitem = new node;
newitem->data=value;
newitem->next=NULL;
return (*newitem); // return the objet: this will be then be converted to a reference
}
You could also work with pointers as suggested by another answer. However in this case, I'd opt for shared_ptr:
shared_ptr<node> create_node(int value) {
node* newitem = new node;
newitem->data=value;
newitem->next=NULL;
return (shared_ptr<node>(newitem));
}
You should return &newitem.
But given the fact that your newitem is only available in this function's scope, the returned pointer will point to a destroyed object, so "nothing", or rather it will result in undefined behavior.
I guess you want your newitem to be created dynamically.
node * create_node(int value)
{
node * newitem = new node;
newitem->data=value;
newitem->next=NULL;
return newitem;
};

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()

How to add a Node pointer to a Vector pointer?

I am trying to create a maze that consists of Nodes objects. Each Node object has a member variable Node *attachedNodes[4] that essentially contains all of the attached Nodes that will later tell the program the options it has when it is doing a breadth first search. Every time I think that I understand pointers, another issue like this comes up, and I feel lost all over again. Especially since it was working fine (as far as I knew) until I changed something that I thought was unrelated. Anyways, here is where the issues are:
My Node object looks like this
class Node {
public:
...
void attachNewNode(Node *newNode, int index);
...
private:
...
Node *attachedNodes[4];
...
};
My function to attach the Nodes looks like this:
void Node::attachNewNode(Node *newNode, int index) {
*attachedNodes[index] = *newNode;
}
And then lastly, the part of the other function that is calling the attachNewNode function looks like this:
int mazeIndex = 0;
while (inStream.peek() != EOF) {
int count = 0;
Node n;
Node m;
...
if (System::isNode(name2)) {
m = System::findNode(name2);
}
else {
m = Node(name2);
maze[mazeIndex] = m;
mazeIndex++;
}
Node *temp;
*temp = m;
n.attachNewNode(temp, count); //The error usually happens here, but I added the rest of the code because through debugging it is only consistently in this whole area.
count++;
}
n.setNumberUsed(count);
}
Sorry that this got a little lengthy, but I've been searching all over this portion that I have provided trying to figure out what is wrong, but it would be nice to have someone that knows a little more about pointers give their input on the matter. The Node class was given to me, but everything else I made, so basically any of that could be changed. Thanks in advance for the help.
Your class contains a property:
Node *attachedNodes[4];
The above says that attachedNodes is an array that contains 4 pointers to Nodes. In your attachNewNode function, you do:
*attachedNodes[index] = *newNode;
This means that you are trying to assign value of newNode (as * dereferences the pointer) to the value of the element under attachedNodes[index]. What you probably want is:
attachedNodes[index] = newNode;
This means that you just want to store the address (as pointer is just an address to some place in memory) in the array of addresses.
There is also another error here:
Node *temp;
*temp = m;
n.attachNewNode(temp, count);
Again, you are interested in storing the address of node m. In order to do that, you need to get the said address:
Node *temp;
temp = &m;
n.attachNewNode(temp, count);
These are the most obvious problems with the above code, but there might be more.

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

Passing a object by reference in c++

This is a noobie question, but I'm not sure how to pass by reference in C++. I have the following class which sets up a Node and a few functions.
class Node
{
public:
Node *next;
int data;
Node(int dat)
{
next = NULL;
data = dat;
}
Node* getNext()
{ return next; }
void setNext(Node *n)
{ next = n;}
void reverse(Node *root)
{
Node *previous = NULL;
while(root != NULL)
{
Node *next = root->getNext();
root->setNext(previous);
previous = root;
root = next;
}
root = previous;
}
};
Now, the purpose of my little class is to create a singularly linked list and have the ability to reverse it. And it seems to work fine, if I return the node named 'previous' at the end of reverse.
But look at my main function:
int main()
{
Node *root = new Node(1);
Node *num2 = new Node(2);
Node *num3 = new Node(3);
Node *num4 = new Node(4);
root->setNext(num2);
num2->setNext(num3);
num3->setNext(num4);
root->printList();
root->reverse(root);
root->printList();
return 0;
}
printList() was omitted for sake of space, but it just prints a list given a node. The problem is, when root->reverse(root) is called, root doesn't actually end up pointing to 'previous'.
The output would be this:
1
2
3
4
// the value of previous from the reverse function is 4
1
I really don't understand the output. Anyone care to explain what's happening? (Why isn't the list reversed even though if I did something like this root = root->reverse(root) where reverse returns previous, it would) why is it that root now only points to itself? I'm new to c++ and appreciate your help!
C++ has support for reference semantics. Therefore, for a given function:
void foo(Bar& bar);
To pass by reference you do:
int main() {
Bar whatsit;
foo(whatsit);
return 0;
}
That's it!
This is commonly confused with passing a pointer, where for a function such as:
void foo(Bar* bar);
You would do:
int main() {
Bar whatisit;
foo(&whatsit);
return 0;
}
The difference is mostly a matter of semantics:
- A reference is always valid. There is no reason to check for a NULL pointer.
- A pointer could be NULL, and as such, should be checked.
It is, however, possible for a reference to refer to a NULL pointer, however, if the programmer decides to be evil and abuse reference semantics, but the principle remains.
You aren't passing by reference. You are passing a copy of the pointer. This copy still points to the same node, but it is still just a copy with local scope. Basically it is another pointer pointing to the node that the pointer in main is pointing to (ha!). At the end of your function, your assignment is assigning previous to this pointer copy, and then the function ends and the copy goes out of scope. Your pointer in main remains unchanged.
The reason returning/assigning the pointer worked is that this copy which has been set to what you want is returned and assigned to your pointer in main.
You can fix this in a multitude of ways. Pass a reference to your pointer (ugly imo), use references, or return root and do an assignment.
To pass a pointer by reference you can declare reverse as:
void reverse(Node*& root) {
// ...
}