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.
Related
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.
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();
}
I'm getting a segmentation fault on this program, and I know it has something to do with a null pointer being dereferenced, but I'm not exactly sure which one is causing the error. I'm just not certain as to how to fix the error while maintaining the purpose of the original program - it will compile, but at runtime I get the segfault I was just talking about.
main:
#include "link.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
link * head_pointer = new link(NULL, NULL) ;
for (int i = 0; i < 10; i++) {
string new_string;
getline(cin, new_string);
string* pointer_to_input = new string(new_string);
link * current_link = new link(head_pointer, pointer_to_input );
head_pointer = current_link;
}
head_pointer -> printAll(*head_pointer);
return 42;
}
link:
#include <string>
#include <iostream>
#include "link.h"
using namespace std;
link::link(link * pointer_to_link, string * pointer_to_string)
{
next = pointer_to_link;
value = pointer_to_string;
}
link::~link() {
delete value;
delete next;
}
link * link::getNext() {
return next;
}
string * link::getString() {
return value;
}
int link::printAll(link link_to_print) {
cout << *link_to_print.getString() << endl;
if (link_to_print.next != NULL) {
return printAll(*link_to_print.getNext());
} else {
return 0;
}
}
Your destructor does look like an error, you shouldn't delete in destructor if you didn't allocate that in constructor:
link::~link() {
}
You should post your link.h to get more detailed explanation.
Without link.h it's not clear what else is wrong, however, there are also other problems:
link::printAll looks like a static method and should be called as: link::printAll(head_pointer);
you printAll should take by pointer, otherwise it it will create a copy of your link and delete it.
printAll has multiple issues as well. Probably it should have been something as follows:
void link::printAll(link *link_to_print)
{
if (!link_to_print)
return;
if (link_to_print->getString())
cout << *link_to_print->getString() << endl;
printAll(link_to_print->next);
}
and your main:
int main()
{
link * head_pointer = new link(NULL, NULL);
for (int i = 0; i < 10; i++) {
string new_string = str;
getline(cin, new_string);
string* pointer_to_input = new string(new_string);
link * current_link = new link(head_pointer, pointer_to_input);
head_pointer = current_link;
}
link::printAll(head_pointer);
return 42;
}
In short to avoid errors you shouldn't store pointers to strings in your link, you should just store strings themselves. Your links perhaps shouldn't assume ownership of other links:
struct link
{
link *next;
string value;
link(link *next, const std::string& value) : next(next), value(value) {}
link * getNext();
const std::string& getString() const;
static void printAll(link *link_to_print);
};
link * link::getNext() {
return next;
}
const string& link::getString() const {
return value;
}
void link::printAll(link *link_to_print)
{
if (!link_to_print)
return;
cout << link_to_print->getString() << endl;
printAll(link_to_print->next);
}
and your main:
int main()
{
link * head_pointer = new link(NULL, "");
for (int i = 0; i < 10; i++) {
string new_string;
getline(cin, new_string);
link * current_link = new link(head_pointer, new_string);
head_pointer = current_link;
}
link::printAll(head_pointer);
// TODO: now you need to walk head_pointer and delete all links manually.
return 42;
}
Once you learn how memory management works in general you should most likely redesign your link using some kind of smart pointer helper class, such as unique_ptr or shared_ptr. And off course, once you master linked list you should start using std::list.
link::printAll takes its argument by value, which has two important effects:
The argument inside the function is a second link object created by making copies of the same value and next pointer.
The copy has automatic storage duration and is destroyed at the end of the function call.
Therefore, you have double frees going on. In particular, both the copy made in the recursive call and the sub-link of the original link share the same value pointer, and both try to delete it. The second deletion causes undefined behavior.
The solution is to respect the rule-of-three and not allow shallow copies of raw pointers. There are two possible approaches for managing objects owned by pointer:
Write a copy constructor to go with your destructor, so the two deletes mentioned above act on two different copies of the value.
OR
Use a smart pointer, such as std::shared_ptr, so you don't have to write a destructor by hand at all.
Note that you need a pointer to implement the connection between objects in the linked list, but you do not need a pointer to store the data. Having a data member of type std::string, instead of std::string *, would be just fine and do the right thing when copied (It makes sense to think of std::string as a smart pointer to an array of characters, that just happens to also have some extra string-manipulation functions tacked on).
When I push a pointer of struct into a std::queue, and then poping the value, the value that I'm getting back would change to zero. I've simplified the actual code to illustrate the problem below. The head pointer in the real code is a class variable and contains other values. If I push head onto the queue, all other values that I get also become uninitialized.
What could be the issue here?
Note: PipePixel *head; is an instance variable declared in the class header file.
Add Head Function:
void LinkedGraph::addHeadPixel(int index) {
PipePixel pixel = {NULL, 433, std::vector<PipePixel*>()};
pixel.index = index;
if (head==NULL) {
pixelMap[index] = &pixel;
head = &pixel;
} else {
printf("Already added head pixel! Px:%d\n", pixelMap[index]->index);
}
}
Print Function: <-- Where problem occurs
std::queue<PipePixel*> printQueue;
printQueue.push(head);
printf("headIndex:%d\n", head->index); // headIndex:433
while (!printQueue.empty()) {
PipePixel *child = printQueue.front();
printf("childIndex:%d\n", child->index); //childIndex:0
printQueue.pop();
if (child == NULL) {
printf("child is null"); // no output
continue;
}
}
PipePixel Struct:
struct PipePixel {
PipePixel *parent;
int index; //pixel index
std::vector<PipePixel*> children;
};
The problem here is that the variable pixel is local inside the LinkedGraph::addHeadPixel function. Once the function returns that object is destructed and the variable ceases to exist. If you have stored a pointer to a local variable, that pointer no longer points to a valid object, and dereferencing the pointer leads to undefined behavior.
My recommendation is to not use pointers at all, but let the compiler handle he object copying. For such small and simple objects its possible performance impact is negligible.
Under which circumstances would you want to use code of this nature in c++?
void foo(type *&in) {...}
void fii() {
type *choochoo;
...
foo(choochoo);
}
You would want to pass a pointer by reference if you have a need to modify the pointer rather than the object that the pointer is pointing to.
This is similar to why double pointers are used; using a reference to a pointer is slightly safer than using pointers.
50% of C++ programmers like to set their pointers to null after a delete:
template<typename T>
void moronic_delete(T*& p)
{
delete p;
p = nullptr;
}
Without the reference, you would only be changing a local copy of the pointer, not affecting the caller.
David's answer is correct, but if it's still a little abstract, here are two examples:
You might want to zero all freed pointers to catch memory problems earlier. C-style you'd do:
void freeAndZero(void** ptr)
{
free(*ptr);
*ptr = 0;
}
void* ptr = malloc(...);
...
freeAndZero(&ptr);
In C++ to do the same, you might do:
template<class T> void freeAndZero(T* &ptr)
{
delete ptr;
ptr = 0;
}
int* ptr = new int;
...
freeAndZero(ptr);
When dealing with linked-lists - often simply represented as pointers to a next node:
struct Node
{
value_t value;
Node* next;
};
In this case, when you insert to the empty list you necessarily must change the incoming pointer because the result is not the NULL pointer anymore. This is a case where you modify an external pointer from a function, so it would have a reference to pointer in its signature:
void insert(Node* &list)
{
...
if(!list) list = new Node(...);
...
}
There's an example in this question.
I have had to use code like this to provide functions to allocate memory to a pointer passed in and return its size because my company "object" to me using the STL
int iSizeOfArray(int* &piArray) {
piArray = new int[iNumberOfElements];
...
return iNumberOfElements;
}
It is not nice, but the pointer must be passed by reference (or use double pointer). If not, memory is allocated to a local copy of the pointer if it is passed by value which results in a memory leak.
One example is when you write a parser function and pass it a source pointer to read from, if the function is supposed to push that pointer forward behind the last character which has been correctly recognized by the parser. Using a reference to a pointer makes it clear then that the function will move the original pointer to update its position.
In general, you use references to pointers if you want to pass a pointer to a function and let it move that original pointer to some other position instead of just moving a copy of it without affecting the original.
Another situation when you may need this is if you have stl collection of pointers and want to change
them using stl algorithm. Example of for_each in c++98.
struct Storage {
typedef std::list<Object*> ObjectList;
ObjectList objects;
void change() {
typedef void (*ChangeFunctionType)(Object*&);
std::for_each<ObjectList::iterator, ChangeFunctionType>
(objects.begin(), objects.end(), &Storage::changeObject);
}
static void changeObject(Object*& item) {
delete item;
item = 0;
if (someCondition) item = new Object();
}
};
Otherwise, if you use changeObject(Object* item) signature you have copy of pointer, not original one.
Refer the code below:
When we pass x as Node *x, a new variable is created with the same address passed on by the caller function.
If you modify the value pointed by the pointer, that change will be reflected in the caller function variable.
But if we change the value of the pointer itself it will not be reflected in the caller function because callee function has the copy of the passed pointer not the original pointer itself.
void increment(int *x) {
(*x)++;
x++;
cout << x << endl; // prints 0x7ffe9f8e1900
}
int main() {
int a = 10;
int *x = &a;
increment(x);
cout << *x << endl; // prints 11
cout << x << endl; // prints 0x7ffe9f8e18fc
return 0;
}
Now, check the below code:
When we pass x as Node *&x, we pass a reference of the original variable present in the caller function meaning these two variable (caller and callee root) are same, their name may differ.
if we modify the value pointer by the pointer, that change will be reflected in the caller function variable.
Now if we change the value of the pointer itself it will also be reflected in the caller function variable.
void increment(int* &x)
{
(*x) ++;
cout << *x << endl; // prints 11
x++;
cout << x << endl; // prints 0x7fffb93eba70
}
int main()
{
int a = 10;
int *x = &a;
increment(x);
cout << *x << endl; // prints garbage
cout << x << endl; // prints 0x7fffb93eba70
return 0;
}