C++ destructor for tree structure - c++

I have this tree structure:
public:
node(string& const n);
virtual ~node();
string get_name() const;
void set_name(string& new_name);
int get_nr_children() const;
node get_child(int i) const;
void add_child(node child);
private:
string& name;
vector<node> children;
};
and my main.cpp looks like this:
int main() {
string s = "root";
node r(s);
string s2 = "left child";
node ls(s2);
string s3 = "right child";
node rs(s3);
r.add_child(ls);
r.add_child(rs);
r.~node();
}
(I know that ~node() is run on all objects anyway at the end of the main funciton, but I want to make sure it is executed on the root r first)
All methods are working fine so far, except for the destructor. This is my first destructor, and I came up with the following recursive try, but don't know why it won't work.
node::~node() {
cout << "Enter ~node of " << this->get_name() << endl;
while (this->get_nr_children() != 0) {
this->get_child(0).~node();
this->children.pop_back();
}
delete this;
cout << "Leave ~node of " << this->get_name() << endl;
}
The result is an endless output of "Enter ~node of left child"

"(I know that ~node() is run on all objects anyway at the end of the main funciton, but I want to make sure it is executed on the root r first)"
This quote is enough to say that everything into this question is based only on misconceptions.
It doesn't even make sense to try to correct: a full rewrite is necessary.
Instead read more about destrcuctors, their invocation and what they are for.
Calling it explicitly does not suppress the implicit call of it. And double destruction is undefined behavior.
Also delete this is something very tricky requiring you must be VERY SURE of what it means.
And accessing class methods (this->...) or data after deleting them ... is only looking for troubles.

This is invalid and yields Undefined Behavior if it compiles:
vector<node> children;
At the point of this data member declaration the class node is incomplete; its size isn't yet known.
You can't use an incomplete type as item type for a standard library container (but you can use pointers).
In the destructor implementation, also
delete this;
yields Undefined Behavior, an infinite recursion calling the destructor which (in this delete expression) calls itself, and so on.
The data member declaration
string& name;
also has a strong, unpleasant odour about it, but since you're not showing the constructor implementations I can't state categorically 100% that it's wrong.
However, given the rest of the code, the chance of this being correct is infinitesimal. Just use
string name_;

Ordinarily, a tree uses nodes that are allocated on the free store. That means trafficking in pointers to nodes, and deleting nodes that are no longer in use. The code in the question doesn't follow that model: it allocates the root node on the stack, and stores node objects rather than pointers within each node. With that code, all of the compiler-generated destructors will work just fine. There is no need for any user-defined destructors.

Related

Memory allocation error when attempting to print contents of a tree in C++

My problem probably has a simple solution that is staring me in the face, but so far I have been unable to find it. I am pretty new to C languages and this is the first program I have written in C++.
I have a function create_complete_tree(int nr_child_nodes, int tree_depth) that makes a tree of depth int tree_depth in which each node (except for the last row) has int nr_child_nodes number of child nodes. create_complete_tree(2,4) makes a tree that starts out like this:
1
/ \
/ \
2 9
/ \ / \
3 6 10 13
/\ /\/\ /\
...
I am trying to make a function print(std::ostream& str) that, when called on the root node of the tree above, prints the tree contents in this format:
node_1
node_2
node_3
node_4
node_5
node_6
node_7
node_8
node_9
node_10
node_11
node_12
node_13
node_14
node_15
I will worry about adding the indents later, but right now I'm just focused on printing the nodes out in the correct order. This is what I have so far:
void node::print(std::ostream& str) {
str << this->get_name() << std::endl;
for (int i = 0; i < this->get_nr_children(); i++) {
node child = (*this->get_child(i));
child.print(str);
}
}
This function prints nodes 1-8 out, but then I get a Segmentation fault: 11 error. I know this error is a result of attempting to access memory that is somehow unavailable/off-limits, but I'm struggling to understand what that really means in my case. My create_complete_tree method looks like this:
void node::create_complete_tree(int nr_child_nodes, int tree_depth) {
if (tree_depth == 1) {
return;
} else {
while (this->get_nr_children() < nr_child_nodes) {
node* new_child = new node();
this->add_child(new_child);
(*new_child).create_complete_tree(nr_child_nodes, tree_depth - 1);
}
}
}
The child node pointers for each node are stored in a vector called child_nodes. Thanks for taking the time to read this. I'd be grateful for any responses that help me find a solution and better understand memory allocation.
Problem
This code very probably infringes the rule of 3. The following statement:
node child = (*this->get_child(i));
creates a clone of the node. If you didn't provide for the rule of 3, but implemented the destructor, the clone will use the same pointers to the same children than the original node. Unfortunately, when you then leave the print() function, the clone gets destroyed and the destructor will destroy the children. All subsequent access to these children will then access an object which no longer exist, which is UB.
Segfault is a possible symptom of UB. I cannot confirm for sure without seing the constructor, copy constructor, assignment and destructor implementation of node. But seing this code, and many similar questions here, I would be surprised that it'd be another issue ;-)
Potential solutions
The correct solution would anyhow be to implement what's missing for the trule of 3. Because you will experience similar problems in many situations if you don't.
Another solution (which is not mutually exclusive) would be to use pointer without cloning:
void node::print(std::ostream& str) {
str << this->get_name() << std::endl;
for (int i = 0; i < get_nr_children(); i++) { // this-> is not needed
node *child = this->get_child(i); // pointer assignment without cloning
child->print(str); // member invokation for a pointer
}
}

How do I read multiple variables into a node?

So my project is to get a file called "contacts.txt", read in the data and put the data into a node. Then, I put that node into a list. I purge duplicates and print out the resulting list. I'm trying to get the reading in the data and the printing part down first but I'm having problem printing out my list.
A line of contact looks like:
Angelina M. Pierre 306 420 1235
And each part of the line (first name, middle initial, last name, phone number) is supposed to have their own variable. I'm not really sure what I'm doing wrong and I would appreciate the help. My code is:
#include <iostream>
#include <bits/stdc++.h>
#include <stdlib.h>
#include <fstream>
using namespace std;
class Node
{
public:
string firstName;
string middleI;
string lastName;
string phoneNum;
Node *next;
};
// This function prints contents of linked list
// starting from the given node
void printList(Node* n)
{
while (n != NULL) {
cout << n->firstName->middleI->lastName->phoneNum << endl;
n = n->next;
}
}
//This function reads the data from a file called "contacts"
//And streams each line into a new node.
void readData(Node* &p)
{
Node *newNode = new Node; /* Initializing the node*/
ifstream fin("C:\\Users\\owner\\Documents\\contacts.txt");
p = newNode;
while(!EOF){
//fin >> firstName >> middleI >> lastName >> phoneNum;
//while(getline(fin,newNode->contacts)){
newNode->firstName;
newNode->middleI;
newNode->lastName;
newNode->phoneNum;
newNode->next = new Node;
newNode = newNode->next;
}
}
// Driver code
int main()
{
Node *head;
readData(head);
printList(head);
return 0;
}
There are a couple things that I think are majorly detracting from your program's performance. In your printList function, you have the line cout << n->firstName->middleI->lastName->phoneNum << endl;, and I assume here you intend to print all of the information for a user. What is happening here, however, is that the program takes the pointer n, attempts to find the firstName property of the object being pointed to, then takes this property and attempts to find the middleI property of that property, then the lastName property of that property, etc. These fields of course do not exist, so your program will likely crash. Rather, I think using something like cout << n->firstName << " " << n->middleI << " " << n->lastName << " " << n->phoneNum << endl; would work better.
Also, in your readData function, your while loop will continue to update the singular node p instead of creating new nodes, so (assuming that your input file is properly formatted and all that jazz) your head node, which is what is passed into this function when it is called by main(), will only be equal to the last contact in your file and your list will have a length of 1.
Incidentally, I see that you only have a Node class. If you are wanting to work with lists, you probably should create a second class (i.e. LinkedList) that takes one more level of abstraction. Your Node class, then, will handle setting/reporting its data and answering which node follows it, and your LinkedList class will handle keeping track of the list (by remembering where the head is), adding to/deleting from the list, and finding specific nodes in the list.
Some other considerations:
Variables held by a class should almost always be private instead of public. The reason for encapsulating the information in the first place, aside from organizing it, is to make sure that other parts of the program that have no business altering this portion of your code cannot touch it, and you lose this safeguard when you make everything public.
The functions that you are using to create/add nodes, print lists, etc., should all be methods (i.e. functions of a particular class). Say I have some class, Foo, which has a function that acts upon it named bar. To implement it, I could write something like:
class Foo {
private:
//Foo's variables
public:
void bar() {
//bar's implementation
}
}
You will be able to use the method bar() elsewhere because it is labeled public, and bar() will be responsible for handling any necessary manipulation of Foo's information.
It is considered bad practice to use using namespace std; because it can sometimes lead to ambiguous function calls and adding std:: is more explicit. See here for more information.
Using the keyword NULL is very C-style, whereas nullptr is considered more proper (and even safer) in C++. If you are curious, this seems to give a pretty in-depth explanation of this change.
Using while(!fin.eof()) is also considered wrong because !fin.eof() will only return true after you have finished reading the input file. Thus, you will attempt to read past the end of the file and this is plain dangerous. See here for more information.
A little lengthy, but I hope this clarifies things for you a bit! Feel free to comment if you have any questions.

Copy constructor for a vector of pointers

I'm trying to create a node class that contains a vector of pointers. Here's my code:
node.h:
#ifndef NODE_H
#define NODE_H
class node
{
public:
vector<node*> next;
void add_arc(node & a)
string some_string;
#endif
node.cpp:
void node::add_arc(node & a)
{
node *b = &a;
next.push_back(b); //only copyies nodes
}
main.cpp:
int main()
{
vector<node> nodes;
node a;
node b;
node c;
a.somestring = "a";
b.somestring = "b";
c.somestring = "c";
a.add_arc(b); //a should point to b
a.add_arc(c); //a should point to c
nodes.push_back(a);
nodes.push_back(b);
nodes.push_back(c);
cout << nodes[0].next.size() << endl; // prints "2", works fine
cout << nodes[0].next[0]->some_string << endl; //empty
}
I thought it would be as easy as just overloading push_back:
void push_back(vertex * pointer)
{
next.push_back(pointer);
}
But I think I really need a copy constructor, or some other method to make this work. How would I go about doing this for a vector of pointers?
Edit: I guess I didn't explain it well. Look at the answers in this question:
Segmentation fault when accessing a pointer's member function in a vector
Making 'a' a reference did not work for me
It works...
Your code generates as expected the correct output (see online demo):
2
b
...However this design is not future proof
However this result is related somehow to luck, because in your code snippet:
the nodes in the nodes vector are copies of the original object including all their pointers
the local objects a, b, c to which these pointers point still exist
However in more complex code, you'd quickly end up with dangling pointers.
Imagine:
Bad example 1: you create a graph, keeping all the nodes directly in a vector of nodes. You then add the first arcs between the nodes. As soon as you'll add a new node to the vector, reallocation might occur and you'd risk to see all your next pointers invalidated.
Bad example 2: you initialise a graph like you did, but in a function called by main. In this case, as soon as you return from this function, all the local nodes get destroyed and the vector's node will point to objects that do no longer exist. UB guaranteed !
How to improve ?
Your design fails to recognize that the nodes all belong to the same graph.
There is a quick and dirty way out: always create the node from the free store, and store them in a vector<node*>.
vector<node*> nodes;
node *a = new node("a"); // Imagine a node constructor
node *b = new node("b");
a->add_arc(b); //change signature, to accept a pointer
nodes.push_back(a);
nodes.push_back(b);
There's a better approach: improve further the previous approach, but use shared_ptr<node*> to make sure that nodes that are no longer referenced (neither by a vector of nodes, nor by an arc) are destroyed automatically.
There's an even better approach: encapsulate the nodes in a class representing a graph. In this case, you could consider using a vector<nodes> and replace the pointers in next, by indexes of the target nodes in the vector. No pointer, but perfect copy of graphs will be much easier. And no more memory management hassle.
class node // just to give the general idea
{
public:
vector<int> next; // not usable without the graph
void add_arc(int a)
string id;
};
class graph {
vector<node> nodes;
public:
void add_node (node a);
void add_arc (string from, string to);
node& operator[] (size_t i);
...
};

Confused with delete keyword operation in C++

I would like to know how delete works?
In main function I have deleted the cfact object. But still the cfact->Hello() works instead of throwing an error.
While debugging I found while delete happens, cfact releases the memory. as soon as factory* c2fact = newfun.Newfun("c2_fact"); line executes cfact gets some memory location.
class factory{
public:
virtual void Hello() = 0;
};
class c_fact: public factory
{
public:
void Hello(){
cout << "class c_fact: public factory"<<endl;
}
};
class c2_fact: public factory
{
public:
void Hello(){
cout << "class c2_fact: public factory"<<endl;
}
};
class callFun{
public:
virtual factory* Newfun(string data)
{
if(data == "c_fact")
{return new c_fact;}
else
{return new c2_fact;}
}
};
class newFun:public callFun{
public:
factory* Newfun(string data)
{
if(data == "c_fact")
{return new c_fact;}
else if (data == "c2_fact")
{return new c2_fact;}
}
};
int main()
{
newFun newfun;
factory* cfact = newfun.Newfun("c_fact");
delete cfact; //Deleted the instance
factory* c2fact = newfun.Newfun("c2_fact");
cfact->Hello();//Still it prints the output
c2fact->Hello();
system("pause");
return 0;
}
delete doesn't actually invalidate what it points to. It just tells the OS that the memory can be used for something else and that the program doesn't need it anymore.
If it not overwritten by other data your data will still be in memory and will still be accessible. This is a cause of many bugs that go undetected during development phase and later show up.
The fact that is is working now doesn't mean it will always work. For example if you move the code to another machine or if you restart your computer the code might segfault.
It is always a good practice to set pointers to NULL after delete. Or even better use smart pointers.
This is undefined behavior, most likely this works because the method Hello is not using any of the classes variables and thus is not using the this pointer. Trying outputting this in Hello and you should see an invalid pointer after the call to delete:
std::cout << std::hex << this << << std::endl ;
In my test case it comes back as 0 after delete
Dereferencing a deleted pointer is undefined behaviour. That means anything can happen, including the program appearing to "work". You cannot rely on any such behaviour.
When you delete the memory it is released. however, the content is usually not changed, so anything that is written in that memory is still there after the delete, but you don't know how long it will stay, as other functions can grab it and overwrite it with their own data.
On some compilers, when compiling in debug mode, the memory is marked, so that you can detect such errors as you did by reusing the deleted pointer. However that is not necessarily the default. So you should never reuse a pointer that was deleted.
Sorry I can't comment...
I compiled your code and you can observe that c2fact replaces the cfact you just destroyed (the output is
class c2_fact: public factory
class c2_fact: public factory
)
BTW if you put "cfact->Hello();" before you create your c2fact, the program may crash (which is what you seem to wish) because the mem blocks are not affected to any object. Note that this behavior may change depending on the memory monitoring and other running processes.

C++: Issue Creating New Instance of Class After Current Instance Destroyed

I am working on a Binary Search Tree (BST) program. Per the assignment's requirements, the user loads a text file to construct the tree. If the user would like, they can then create a new tree by loading a new text file. Loading a new text file should destroy the old tree.
To accommodate this require, my method to create a new tree, readNewFile(), first checks if a tree already exists. If it does, it runs the destructor on the tree. However, I then need to create a new tree, that exists outside the scope of readNewFile(), so that it can be accessed globally. Is this possible to do? If so, could you please explain how?
My reduced code:
int main() {
//BST
BST rootTree;
readNewFile(rootTree);
readNewFile(rootTree);
return 0;
}
void readNewFile(BST& tree) {
ifstream inFile;
string fileName;
// if tree was previously filled, destroy it
if (tree.rootPtr() != NULL) {
tree.~BST();
BST tree = new BST();
}
cout << "\nEnter file to load: ";
cin.ignore();
getline(cin, fileName);
cout << "Opening file " << fileName << endl;
inFile.open(fileName.c_str(), ios::in);
// Populates tree... //
}
Destructor (within BST.hpp):
BST::~BST() {
destroyTree(root);
}
void BST::destroyTree(TreeNode*& treePtr) {
if (treePtr != NULL) {
destroyTree(treePtr->leftChildPtr);
destroyTree(treePtr->rightChildPtr);
delete treePtr;
}
}
This returns a segfault, which makes sense, since the tree was destroyed. However, is there a way I can create a new tree, with the same scope as the destroyed BST rootTree?
One way to accomplish the requirement is to have a method called del() in your BST class. All it does is delete all the nodes of the tree but not the root pointer. This is the pointer that points to the root node. After calling del(), you can start creating a new tree. The pseudo code would look something like this:
// if tree was previously filled, destroy it
if (tree.rootPtr() != NULL) {
tree.del()
}
// read the input file
// Start inserting the new nodes
First off: what's wrong with the code.
As you already pointed out, if the tree is destroyed, you can't be using it again. In this case, it's double-bad: by calling the destructor on BST in readNewFile(), you're causing the destructor to be called twice -- once when you explicitly call it, and the second time when the local instance in main() goes out of scope. This is bad.
Now about how to fix it:
The easiest way would just to declare rootTree as a pointer inside main(), and then make readNewFile() take a pointer-to-pointer as an argument. readNewFile() would destroy the existing tree pointed to by the pointer, and then reset the pointer to point at the new tree it creates. Simple.
What would be a better design, though, would be to make readNewFile() a member function of BST. Then main() should construct a new BST and call that instance's readNewFile().
You never invoke the destructor directly unless you know pretty well what you're doing. And then, it's typically because it was created using placement new. Further, "T t = new T;" doesn't make sense, assigning a pointer-to-T to a T. My guess is you are reproducing a Javaism here, but the object models of these two languages are too different.