How do I delete map<char, map<char, char>> board_game, map<int, char> X_index and list<Node*>?
How would I write a proper destructor for the classes Tree, Node and Boardgame?
class Search_tree {
Node* root = nullptr;
char playerColor;
list<Node*> leaveNodes;
// Constructor, functions ...
~ Search_tree(); <--?
}
class Node {
Board_game* currentBoard = nullptr;
Node* parent = nullptr;
list<Node*> childs;
// Constructor, functions ...
~Node(); <--?
}
class Board_game {
public:
// Boardgame
map<char, map<char, char>> board_game;
map<int, char> X_index;
map<int, char> Y_index;
// Figures
Position figures[8];
// Constructor, functions ...
~Board_game(); <--?
}
struct Position {
char x;
char y;
};
You need to decide who owns what. Then you should turn those "owning" raw pointers into std::unique_ptr and then you won't need hand-written destructors. A possible ownership structure might be:
class Search_tree {
std::unique_ptr<Node> root;
char playerColor;
list<Node*> leaveNodes;
}
class Node {
Board_game* currentBoard = nullptr;
Node* parent = nullptr;
list<std::unique_ptr<Node>> childs;
}
Since Board_game does not contain any raw pointers, it already doesn't need a hand-written destructor.
Related
I have made a superclass named "tree". I have constructed the tree in this class. Now, I want to pass the root of the constructed tree to another class which is a subclass of tree. But when I try to pass it, the subclass calls the supercalss constructor and sets it to NULL;
struct node
{
struct node *left;
struct node *right;
int val;
};
struct node *create(int val)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
};
class tree
{
public:
struct node *root;
tree()
{
root = NULL;
}
void createtree()
{
root = create(5);
}
void preorder()
{
preorderp(root);
}
void preorderp(struct node *p)
{
if(!p) {
return;
}
cout<<p->val<<' ';
preorderp(p->left);
preorderp(p->right);
}
};
This is the definition of my tree class. It just creates a tree with one node having value 5. Now I want to pass the new root created to a subclass of tree.
class treeiterator:public tree
{
struct node *p;
stack<struct node *> s;
public:
treeiterator()
{
p = root;
push(root);
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
I create an object for tree first and then do createtree. Now, when I create an object for treeiterator, it's member p gets sets to NULL since supercalss constructor is also called. How can I just access the tree created in the superclass in subclass?
Full code:
#include <bits/stdc++.h>
using namespace std;
struct node
{
struct node *left;
struct node *right;
int val;
};
struct node *create(int val)
{
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp->val = val;
temp->left = temp->right = NULL;
return temp;
};
class tree
{
public:
struct node *root;
tree()
{
root = NULL;
}
void createtree()
{
root = create(5);
}
void preorder()
{
preorderp(root);
}
void preorderp(struct node *p)
{
if(!p) {
return;
}
cout<<p->val<<' ';
preorderp(p->left);
preorderp(p->right);
}
};
class treeiterator:public tree
{
struct node *p;
stack<struct node *> s;
public:
treeiterator()
{
p = root;
push(root);
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
void treeiterator::push(struct node *t)
{
while(t) {
s.push(t);
t = t->left;
}
}
bool treeiterator::hasnext()
{
return s.empty()?1:0;
}
int treeiterator::next()
{
struct node *t = s.top();
int val = t->val;
s.pop();
if(t->right) {
push(t->right);
}
return val;
}
int main()
{
tree t;
t.createtree();
t.preorder();
treeiterator it;
while(it.hasnext()) {
cout<<it.next()<<' ';
}
}
Because of inheritance every treeiterator is also a tree. This means
treeiterator treeIt;
treeIt.createtree();
will do what OP wants. There is no need to make a separate tree and moving the root around.
However this is a bit odd in the world of C++ because OP is under-using the constructor. For example, node could be:
struct node
{
node *left;
node *right;
int val;
node(int inval):
val(inval),
left(nullptr),
right(nullptr)
// the above is a Member Initializer List. It makes sure all of your
// members are initialized before the body of the constructor runs.
{
}
};
That bit after the : in the constructor is the Member Initializer List.
Now when you allocate a node it's initialized and ready to be linked. For tree
class tree
{
public:
struct node *root; // almost certainly should not be public.
// also should be a std::unique_ptr<node>
tree(int inval)
{
root = new node(5); // note new in place of malloc. new allocates
// storage and calls constructors. malloc should
// only be used in C++ in rare edge-cases.
}
/* obsolete
void createtree()
{
root = create(5);
}
*/
...
};
tree is assigned a root on allocation. treeiterator is a wee bit trickier because it must call tree's constructor to set up root.
class treeiterator:public tree
{
struct node *p; // Don't see the point off this
stack<struct node *> s; // or this, but that's another question
public:
treeiterator(int inval):
tree(inval) // call's tree's constructor
{
}
bool hasnext();
int next();
private:
void push(struct node *root);
};
Allocating a treeiterator now guarantees that it is all ready to go with no further work.
treeiterator treeIt(5); // all done.
All of the above is covered within the first few chapters of any good C++ programming text. I recommend getting one and reading it, because right now it looks like you are trying to write bad C.
Off topic 1:
You are going to quickly find that this code is in violation of the Rule Of Three. What is The Rule of Three? If you don't know, read the link. It will save you much time and hair-pulling
Off Topic 2:
#include <bits/stdc++.h>
using namespace std;
Is a ticking time bomb. The first line includes the entire standard library, but only in GCC. Your code is now doing far, far more work than it need to to compile, is no longer standard C++, and is not portable to other compilers and may well break with the next revision of GCC. Don't use anything in bits. It internal compiler-specific stuff with no guarantees what-so-ever.
More here: Why should I not #include <bits/stdc++.h>?
The second line takes everything in the std namespace and places it in the global namespace. This leads to fun games like is reverse or std::reverse being called? Often this leads to insane and arcane compiler messages because the poor compiler is confused as hell, but sometimes it's not confused and picks the best choice among the many and silently breaks something else. Great fun debugging.
More here: Why is "using namespace std" considered bad practice?
Together you have the entire standard library pulled into your file AND stripped of it's proper namespace. This results in a vast minefield of potential hidden pain that is not worth any perceived time savings. One of the resulting bugs could cost more clean up than years of typing a few extra lines per file and characters.
No one want to clean up code with this stupid a mistake, so doing this in a professional setting can be costly.
First, you should not have root has public. This is a gross OO error. If you want it to be available to subclasses you should make it protected.
struct node {
std::vector<struct node*> * list;
}
int main() {
struct node * n = new struct node;
n->list = new std::vector<struct node*>();
n->list->push_back(n);
return 0;
}
How can I delete the n->list with freeing all the pointers that the list is storing?
Will it be n->list->clear()? Or do I have to traverse n->list and call delete or free operator on each element in the list.
std::vector does not assume ownership of dynamically created objects.
(Even if it wanted to, or you created a specialisation or your own implementation, it's impossible to distinguish dynamic allocations from other pointers.)
You need to traverse the vector and free the elements.
The safer/simpler would be
struct node {
std::vector<node> list;
};
int main() {
node n;
n.list.resize(1);
}
or if you need pointer:
struct node {
std::vector<std::unique_ptr<node>> list;
};
int main() {
node n;
n.list.push_back(std::make_unique<node>());
}
First of all: you don't need so much pointers.
If you want it be be this way, you should delete it exactly the same way you have 'newed' it :).
In your example:
int main() {
struct node * n = new struct node;
n->list = new std::vector<struct node*>();
n->list->push_back(n);
delete n->list; // here's the change
delete n; // another required delete
return 0;
}
But as I said, too much news.
You can write your struct node as:
struct node {
std::vector<struct node*> list;
}
it will cause the list to be automatically deleted when node object is being deleted.
This line: struct node * n = new struct node; also can be converted into:
node n;
I have the following code:
class Node;
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
class Node{
public:
std::string getName();
std::vector<Edge> getEdges();
};
when I am trying to compile the compiler claims that OriginNode and TargetNode have incomplete type. I have already forward declare the Node. How can I fix that?
You can't without providing a full definition of Node. You can alternatively declare pointers as members: Node* OriginNode.
I'd suggest you re-think your design though - does an Edge really have a Node. As in - does it have ownership over it? Can't a Node be shared between multiple edges? Also, Does a Node really contain multiple edges?
With boost::container you can change the order of the declarations because it support containers of incomplete types :
class Edge;
class Node{
public:
std::string getName();
boost::container::vector<Edge> getEdges();
};
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
By the way, why do you want to return a value of the Edge vector when you get them from the Node and why do you store the value of the OriginNode and TargetNode inside the edge, you can use references or pointers instead (maybe I'm wrong, I don't know all your requirements).
You should reverse the order of declarations
class Edge;
class Node{
public:
std::string getName();
std::vector<Edge> getEdges();
};
class Edge {
public:
//Edge(Node originnode,Node targetnode,int weight):OriginNode(originnode),TargetNode(targetnode),Weight(weight){};
//~Edge(){};
//Node getOriginNode() const { return OriginNode;};
//Node getTargetNode() const { return TargetNode;};
int getWeight() const { return Weight;};
Node OriginNode;
Node TargetNode;
int Weight;
};
Nevertheless I consider that design of classes as very bad. Node is a primitive entity that should not contain a vector of Edge. Why should Node control the container?! The container is a more high -level generalization than Node. So it should be placed in a more high level compared with Node.
I always seem to get in trouble when I'm deleting all nodes from a tree. I am trying to release all the memory I allocated when creating a trie tree.
I am suppose to create a function remove_all
Is it enough to delete just the "root"
something like this:
void PrefixStringSet::remove_all(NodePtr node)
{
delete root;
}
Or do I have to delete each node with something like this:
void PrefixStringSet::remove_all(NodePtr node)
{
if(!root)
{
return;
}
remove_all(root->children);
delete root;
}
Obviously neither of these are working or I wouldn't be here :).
Other question. Do I have to call the remove_all function in my main function if my destructor is implemented like this
PrefixStringSet::~PrefixStringSet()
{
remove_all(root);
}
Or does the destructor automatically delete the trees/nodes I create?
Edit
struct TrieNode
{
TrieNode(bool present = false);
bool is_leaf();
bool present;
TrieNode* children[ALPHABET_SIZE];
};
class PrefixStringSet
{
public:
// Creates an empty prefix string set.
PrefixStringSet();
~PrefixStringSet();
bool insert(string s);
bool contains(string s);
private:
NodePtr root;
void remove_all(NodePtr node);
};
typedef TrieNode* NodePtr;
Deleting only root is not enough: when deleting a root, you should check whether its children aren't empty, and if they are not empty, recursively delete them. C++ doesn't have garbage collector to do the work for you :)
If your remove_all method is within the destructor of the wrapper object, then you don't have to call it separately.
You should write a remove method in all classes you want to delete at runtime.
So you can delete a tree with little care about garbage collection.
It's easy to use pointer in this way:
class a
{
public:
a(){}
~a(){remove();}
init(int v){
var = new int;
*var=v; }
remove(){delete var;}
private:
int *var;
};
class b
{
public:
b(){}
~b(){remove();}
init(int v){
var = new a;
var->init(v); }
remove(){
var->remove();
delete var; }
private:
a *var;
};
To answer your question: No, deleting root is not enough.
edit: sry i made a mistake at a:init(). I forgot to derefer the pointer.
In Cpp:
void deleteAll(Node* curNode) {
for (int i = 0; i < 26; i++) {
if (NULL != curNode->child[i]) {
deleteAll(curNode->child[i]);
}
}
delete curNode;
}
deleteAll(root);
I'm coming from a Python background, so forgive me on this one. Though I will provide the Python equivalent of what I'm looking for.
I'm creating a list of network nodes, so I wanted to create a class, "Node", that stores their MAC, IP address, and Hostnames, along with a function that prints them out prettily. The following is my code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Node {
string MAC, IP, Hostname;
public:
void set_values(string M, string I, string H);
string list() {return "MAC: "+MAC+"\nIP: "+IP+"\nHostname: "+Hostname+"\n";}
};
void Node::set_values(string M, string I, string H) {
MAC = M;
IP = I;
Hostname = H;
}
int main(int argc, char* argv[])
{
Node firstnode;
firstnode.set_values("C0:FF:EE:C0:FF:EE","192.168.1.60","My-PC");
cout<<firstnode.list();
}
Which prints this out when I run it:
MAC: C0:FF:EE:C0:FF:EE
IP: 192.168.1.60
Hostname: My-PC
What I want is to have these objects automatically added to a vector called NodeList upon creation. For example, here is how I did that in Python:
RecordersList=[]
class Recorder:
def __init__(self, ARecorder, BRecorder, CRecorder):
self.ARecorder = ARecorder
self.BRecorder = BRecorder
self.CRecorder = CRecorder
RecordersList.append(self)
I tried a similar move, where I put the line:
vector<Node> NodeList; before the class declaration (and NodeList.push_back(this); as a Public function), and tried after the class declaration, but either way the compiler isn't aware of the Node class by the time the vector is declared, or vice versa the Node class isn't aware of the NodeList vector.
Is there a way to do this? It would be self-referencial class appending to an existing vector whose type is of that class.
Sure: declare and define a static member in the class, push the this pointer onto it:
class Foo; // forward declaration to make vector happy
class Foo {
private:
static std::vector<Foo *> store;
public:
Foo() { store.push_back(this); }
};
std::vector<Foo *> Foo::store;
Do it explicitly:
std::map<std::string, Node> map;
map[mac1] = Node(mac1,...);
map[mac2] = Node(mac2,...);
In my experience, this sort of design will often not end well due to having to manually manage memory in C++. this is a raw pointer to the object and it is not managed.
You can do this:
class Node; // forward declaration
std::vector<Node*> NodeList;
class Node
{
public:
Node()
{
NodeList.push_back(this); // pass a POINTER to this object
}
};
int main(int argc, char* argv[])
{
Node* node1 = new Node(); // allocated a Node
Node* node2 = new Node(); // allocated a Node
// ...
// deallocate ALL nodes
std::vector<Node*>::iterator it = NodeList.begin();
while (it != NodeList.end())
{
delete *it;
++it;
}
NodeList.clear();
}
The problem with this solution is if you have pointers pointing to indivual nodes. You could end up with dangling pointers and memory corruption.
And alternative solution is:
class Node
{
public:
Node();
};
std::vector<Node> NodeList;
Node::Node()
{
NodeList.push_back(*this); // pass a REFERENCE to this object
}
int main(int argc, char* argv[])
{
Node node1; // create a node
Node node2; // create a node
// ...
}
The problem with this alternative design is that each node passed to NodeList will be a new COPY of that node. So if you do:
int main(int argc, char* argv[])
{
Node node1; // NodeList[0] is logically equal to node1
node1.DoStuffThatModifiesTheContent();
// At this point, node1 is no longer a logical equivalent of NodeList[0]
}
A better design would involve creating a NodeManager class of some sort, and creating and accessing nodes through this manager, which would control the lifetime of all the node objects.