Passing an object by reference (C++) [duplicate] - c++

This question already has answers here:
How to pass a pointer variable as a reference parameter?
(2 answers)
Reason to Pass a Pointer by Reference in C++?
(7 answers)
C++ passing pointer reference
(3 answers)
Closed 8 months ago.
I want a method that creates a binary tree from an array and returns nothing. So I would have to work by reference but I am having some troubles with the proper syntax to use.
I have obviously tried to search before posting this question, I have seen similar posts but no answer were truly helpfull.
Here what i have done so far :
My Class :
class Node
{
private:
int data;
Node* left;
Node* right;
public:
[...]
void make_tree(Node* node, int values[], int size);
};
The method :
// Every operations are done a copy of node, I want them to be done on the original object
void Node::make_tree(Node* node, int values[], int size)
{
if (size <= 0)
{
return;
}
else
{
if (!node)
{
node = new Node(values[size]);
}
else if (!node->has_data())
{
node->set_data(values[size]);
}
// recursive call
make_tree(node->left, values, size - 1);
make_tree(node->right, values, size - 1);
}
}
The call :
int main()
{
int tab[] = { 5,3,4,9,7,6 };
Node* root = new Node();
/* I want "root" to be passed by reference so every modifications
are done on the original object and not a copy who will be destroyed
at the end of the method scope. */
root->make_tree(root, tab, 6);
root->print_tree(); // there is nothing more in root
}
Since I am already passing a pointer to the object "root", I am confused on how I could do it.
Thank you.
PS: I am aware that my recursive call does not do what I described it should do. That is a problem for an other time.
PPS : first post btw, so if you see something I did wrong, please, tell me.

void Node::make_tree(Node* node, int values[], int size);
Node pointer cannot be modified inside the function, as you pass it by value (only the copy is modified).
You can use a reference, as suggested in comments :
void Node::make_tree(Node* &node, int values[], int size);
Or you can also use a pointer to a pointer void Node::make_tree(Node** node, int values[], int size); but there will be more work to modify your code.

Related

C++ Vector not changing value after being altered in a method

I'm trying to create a class for a node in a directed graph (I don't know much about them so forgive if I've messed up any terms).
Whenever I add a pointer to n2 to n1's outNodes vector, I want a pointer to n1 to be added to n2's inNodes vector. I hope that made sense and here is my code.
#include <iostream>
#include <vector>
class Node {
private:
static int nextId;
int id;
std::vector<Node*> ptr_outNodes;
std::vector<Node*> ptr_inNodes;
public:
Node() {
id = nextId++;
}
int getId() {
return id;
}
void setInNodes(Node n) {
ptr_inNodes.push_back(&n);
}
void setOutNodes(Node n) {
ptr_outNodes.push_back(&n);
n.setInNodes(*this);
}
std::vector<Node*> getOutNodes() {
return ptr_outNodes;
}
std::vector<Node*> getInNodes() {
return ptr_inNodes;
}
};
int Node::nextId = 0;
int main() {
Node n1;
Node n2;
n1.setOutNodes(n2);
std::cout << n2.getInNodes().size();
return 0;
}
As you can see, I have it set to return the size of n2's inNodes. When I run the program I see that it's size is 0. If I print out the size within the setInNodes method, I get the result 1 which is odd to me. Also, if I change my main function to this:
int main() {
Node n1;
Node n2;
n1.setOutNodes(n2);
n2.setInNodes(n1);
std::cout << n2.getInNodes().size();
return 0;
}
I get the result 1. Adding that line shows that the function is working, so I believe something is going wrong when I call setInNodes() from setOutNodes(). I've been staring at this for the past half hour, so if someone could help me that would be great, thanks!
You are providing the methods setInNodes and setOutNodes with copies of the original Node object. The pointer you're pushing into the vector is the address of that copy, not of the original object.
To push the address of the original Node object, you need to pass a Node-pointer to the function.
Code:
... // Your Node class code
void setInNodes(Node *n) {
ptr_inNodes.push_back(n);
}
void setOutNodes(Node *n) {
ptr_outNodes.push_back(n);
n.setInNodes(this);
}
...
// in the main function:
n1.setOutNodes(&n2);
n2.setInNodes(&n1);
In your code :
void setInNodes(Node n) {
ptr_inNodes.push_back(&n);
}
void setOutNodes(Node n) {
ptr_outNodes.push_back(&n);
n.setInNodes(*this);
}
You're passing Node by value (its a temporary). Then you're adding the pointer to the temporary to you're vector. When you're function (setxxx) goes out of scope, the temporary is destroyed, and hence the stored pointer is a pointer to an invalid object. Accessing/dereferencing the pointer after the function exits is undefined behavior (ie the program can do anything).
As mentioned elsewhere you can either pass in a pointer or a reference.
void setXxNode(Node& node)...
Passing by reference would be my choice, as it requires a value (shows intent). One then adds the address of the reference to the vector, but note that the lifetime of object referred to must exceed that of the object that now holds the pointer.

Memory allocation In Tree

Hello everyone i wish you are having a great day, i have a problem with allocation memory for my tree with some code i think it's easier to explain and understand.
#define H 7
class Node{
public:
int node_number;
int depth;
int value;
Node* nodes[L];
public:
Node new_node(int node_number,int depth,int value);
void add_node(Node root_node,Node new_node);
void print_node(Node print_node);
};
To create a node my function is here
Node Node::new_node(int node_number,int depth,int value){
Node x;
x.node_number=node_number;
x.depth=depth;
x.value=value;
x.nodes[L]=(Node*) std::malloc(L*sizeof(Node));
return x;
}
and now when i want to add nodes in the node him self like declared in the class i got Segmentation fault (core dumped)
void Node::add_node(Node root_node,Node new_node){
root_node.nodes[0]=&(new_node);
}
My main function
Node root_node;
root_node=root_node.new_node(10,2,23);
Node x;
x=x.new_node(17,19,7);
root_node.add_node(root_node,x);
root_node.print_node(root_node);
Thank you so much
There are few problems here. Firstly you're not actually allocating any new memory. The line in the new_node method
Node x;
is a local variable so it will be destroyed when the method completes, the method then returns a copy of this object on the stack.
Then in the add_node method there is another problem:
root_node.nodes[0]=&(new_node);
This line doesn't call the node_node method, it actually takes the address of the function. Even if it did call the method it would be returning a copy of the object on the stack not a pointer to an object on the heap which is what you need.
Your code doesn't show the definition of L, I'm going to assume that it is a macro definition. Your new_node method should look like this, node the new reserved word, this is where the new object is created on the heap:
Node* Node::new_node(int node_number,int depth,int value){
Node *x = new Node;
x->node_number=node_number;
x->depth=depth;
x->value=value;
// x->nodes[L]=(Node*) std::malloc(L*sizeof(Node));
// not needed if L is a macro and needs correcting if L is a variable
return x;
}
Now this method returns a pointer to a new object on the heap.
Your add_node method will then look like this:
void Node::add_node(Node root_node,Node new_node){
root_node.nodes[0]=new_node(/* Need to add params here! */);
}
However there is a much better way of doing what you want here. You should write a constructor for the Node class like below:
Node::Node(int node_number,int depth,int value)
{
this->node_number = node_number;
this->depth = depth;
this->value = value;
}
This removes the need for the new_node method and means your add_node method will look like this:
void Node::add_node(Node root_node,Node new_node){
root_node.nodes[0]=new Node(/* Need to add params here! */);
}
Hope this helps.
Although there is already a complete answer provided by PeteBlackerThe3rd, I deem it worthy to also provide an answer that does not use any manual memory allocation as this is often the preferred way in C++.
I took the liberty to make some minor adjustments, e.g., when adding a node it is not necessary to provide the depth in the tree as this can be derived from its parent's node.
The struct uses a std::vector which has (at least) two benefits compared to the code provided in the question. First, there is no need to know the maximum number of children nodes during compile time. If you want to fix this during compile time one can easily replace the std::vector by std::array. Second, there is no need to manually free memory at destruction as this is all taken care of by std::vector.
#include <iomanip>
#include <vector>
struct Node
{
// I expect these data members to be constants
int const d_nodeNumber;
int const d_depth;
int const d_value;
std::vector<Node> d_childNodes;
Node() = delete;
Node(int number, int depth, int value)
:
d_nodeNumber (number),
d_depth (depth),
d_value (value),
d_childNodes ()
{ }
/*
* Note that this function does not ask for a 'depth' argument
* As the depth of a child is always the depth of its parent + 1
*/
void addChildNode (int number, int value)
{
d_childNodes.emplace_back(number, d_depth + 1, value);
}
/*
* Just an arbitrarily function to generate some output
*/
void showTreeFromHere() const
{
int const n = 1 + 2 * d_depth;
std::cout << std::setw(n) << ' '
<< std::setw(5) << d_nodeNumber
<< std::setw(5) << d_depth
<< std::setw(5) << d_value << std::endl;
for (Node const &n: d_childNodes)
n.showTreeFromHere();
}
};
The struct can be used as follows:
int main()
{
Node root_node(0,0,0);
// Add two child nodes
root_node.addChildNode(1,1);
root_node.addChildNode(2,1);
// Add six grandchildren
root_node.d_childNodes[0].addChildNode(3,8);
root_node.d_childNodes[0].addChildNode(4,8);
root_node.d_childNodes[0].addChildNode(5,8);
root_node.d_childNodes[1].addChildNode(6,8);
root_node.d_childNodes[1].addChildNode(7,8);
root_node.d_childNodes[1].addChildNode(8,8);
root_node.showTreeFromHere();
}

C++ - Setting a node to NULL doesn't work [duplicate]

This question already has answers here:
Function does not change passed pointer C++
(4 answers)
Closed 5 years ago.
#include <iostream>
using namespace std;
struct node{
int val;
node* left, *right;
};
void _delete(node *root)
{
root = NULL;
}
void change(node *root)
{
root->val = 6;
}
int main()
{
node * root = new node;
root->val = 5;
change(root);
_delete(root);
cout<<root->val<<endl;
return 0;
}
The output of the above program is 6. It seems as if the _delete function has no effect on the root node but change function has an effect on the root node. It is almost as if delete treats the argument passed as a local variable but change treats the argument as a global variable. Is there anything that I am missing out or is this normal? If it is normal, please explain.
Since you pass the pointer by value in your _delete function, the value in the caller is not changed.
The quickest fix is to write
void _delete(node*& root)
i.e. pass the pointer by reference: note the &; you might also want to call delete on the pointer there too else you leak memory. The function change works as it is since you are using the pointer to member operator ->.

Why can a reference save something a pointer points to even if the pointer has been deleted? [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 6 years ago.
Improve this question
When I'm learning data structure at the binomial heap, I read Weiss's code implementation. Some code as follow:
node implementation and deleteMin algorithm are like:
template<typename Comparable>
struct BinomialNode
{
Comparable element;
BinomialNode *leftChild;
BinomialNode *nextSibling;
};
void deleteMin( Comparable & minItem )
{
int minIndex = findMinIndex( );
minItem = theTrees[ minIndex ]->element;
BinomialNode *oldRoot = theTrees[ minIndex ];
BinomialNode *deletedTree = oldRoot->leftChild;
delete oldRoot;
}
But I'm confused by the "Comparable & minItem". As we see, the "minItem" saves the element. But soon the "oldRoot" has been deleted! The "element" member is inside of the "oldRoot"! Can someone tell me the principle of the status...
I also made some other tests.
struct Node{
int i;
Node * next;
Node(int i, Node* next = nullptr): i(i), next(next){}
};
void getInt(int & i){
int * p = new int(3);
i = *p;
delete p; //the reference can get the true value??? =>output: 3(right)
}
void getInt(int * &i){
int * p = new int(3);
i = p;
delete p; //pointer can't get the real number because of deletion => output: 6904432(wrong)
}
int main() //for test
{
Node* child = new Node(3);
Node* root = new Node(1, child);
int i;
getInt(i);
cout << i << endl;
int * m;
getInt(m);
cout << *m;
}
I've learnt about the bottom implementation of the reference & is the point *.
But why & can get the real value... I feel confused. Thx!!
If you ask whether there is something wrong with the the binomial code, then the answer is no, there is nothing wrong with assigning to the parameter.
In the first code, minItem = theTrees[ minIndex ]->element; copies the object to the object that is passed as reference, so afterwards there is no reference to anything that was deleted (assuming Comparable has no knowledge of BinomialNode). The reference of the parameter refers to the passed object not to anything in the data-structure.
The same goes for the test: after getInt(i), int just contains 3.
However, void getInt(int * &i) returns a dangling pointer, so this is bad code.
Edit out of completeness: the answer was addressing the assumed issue with the reference parameter, but the binomial code void deleteMin( Comparable & minItem ) contains 2 issues, hopefully addressed later in the book:
the case where findMinIndex() fails isn't handled. What happens with an empty heap?
BinomialNode *deletedTree = oldRoot->leftChild;: nothing is done with deletedTree, which at least causes a memory leak and actually loses information.

C++ stack implementation, not reserving memory in function [duplicate]

This question already has answers here:
Passing a bool as a param. C++
(2 answers)
Closed 9 years ago.
Hello I want to write stack implementation, unfortunately something went wrong
CPP FILE
Node* head=0;
std::cout << "front insertion" << std::endl;
addBeg(head, 1);
std::cout<<head<<std::endl;
HEADER FILE
class Node
{public:
int value;
class Node *next_el;
Node(int value){ this->value=value;next_el=NULL;}
};
void addBeg(Node *head, int value){
head=new Node(value); //even that doesn't work!?
}
I would really like to know why "head" in main is still NULL value;
What do I do wrong?
You can fix this by changing the header, but it's underhanded:
void addBeg(Node * &head, int value){
head=new Node(value); // now it works
}
Both versions are invoked the same way in the code. Changing a function this way (to take an argument by reference instead of by value) could really trip up users, but I guess in this case it doesn't matter.
If you want to write your own linked list implementation (instead of just using, what is already there, like std::list), I recommend, that you take a look, first, about how linked lists work in C (not C++). A tutorial can be found here for example: http://www.codeproject.com/Articles/24684/How-to-create-Linked-list-using-C-C
Once you have it working in C, you can try to write a C++ "wrapper" around it as a class or template. Other than that, your question is not really precise enough to know, how exactly your list should work.
You are modifying pointer value only inside the addBeg() function, but you want to change value of the variable. Reminds me when i had similar problem and my teacher said "If it doesn't work, add asterisks"
So here it is:
class Node
{public:
int value;
class Node *next_el;
Node(int value){ this->value=value;next_el=NULL;}
};
void addBeg(Node **head, int value){
*head=new Node(value); //even that doesn't work!?
}
Node* head=0;
std::cout << "front insertion" << std::endl;
addBeg(&head, 1);//notice &
std::cout<<head<<std::endl;
The other solution would be to use reference as shown in #Beta's answer