How should I write destructor for this class in C++? - c++

I have a class that has this kind of structure:
class myClass(){
public:
myClass(){//empty constructor}
void insertRecursively(string word) {
myClass* node = this;
for (int i = 0; i < word.length(); i++) {
if (node->map.find(word.at(i)) == node->map.end()) {
node->map[word.at(i)] = new myClass();
}
node = node->map[word.at(i)];
}
node->isEnd = true;
}
private:
unordered_map<char, myClass*> map = {};
bool isEnd = false;
}
I tried write destructor in this way but it gives me error 'std::bad_alloc':
~myClass() {
clear(map);
}
void clear(unordered_map<char, myClass*> map) {
for (auto& pair : map) {
if (pair.second != nullptr) {
clear(pair.second->map);
}
delete pair.second;
}
}
From what I known so far, I allocated memory on heap by using new keyword, so I should create destructor for myClass. I need to do this recursively because map contains pointers to other myClass pointers.
I've researched several hours and still cannot figure it out.
Can anyone help me to spot the problem that will cause 'std::bad_alloc' ?
My entire code:
class Trie {
public:
Trie() {
}
void insert(string word) {
Trie* node = this;
for (int i = 0; i < word.length(); i++) {
if (node->map.find(word.at(i)) == node->map.end()) {
node->map[word.at(i)] = new Trie();
}
node = node->map[word.at(i)];
}
node->isEnd = true;
}
bool search(string word) {
Trie* node = this;
for (int i = 0; i < word.length(); i++) {
if (node->map.find(word.at(i)) == node->map.end()) {
return false;
} else {
node = node->map[word.at(i)];
}
}
return node->isEnd;
}
bool startsWith(string prefix) {
Trie* node = this;
for (int i = 0; i < prefix.length(); i++) {
if (node->map.find(prefix.at(i)) == node->map.end()) {
return false;
} else {
node = node->map[prefix.at(i)];
}
}
return true;
}
~Trie() {
clear(map);
}
void clear(unordered_map<char, Trie*> map) {
for (auto& pair : map) {
if (pair.second != nullptr) {
clear(pair.second->map);
}
delete pair.second;
}
}
private:
unordered_map<char, Trie*> map = {};
bool isEnd = false;
};

I draw your attention to the following lines of code.
unordered_map<char, myClass*> map = {};
void clear(unordered_map<char, myClass> map)
Trimming a few characters...
unordered_map<char, myClass*> map
void clear(unordered_map<char, myClass> map)
Observe that you declared the local item map over char and myClass*, but you declared clear() as operating on a map over char and myClass, as opposed to a map over char and myClass*.
The * makes a difference.

Either you start to use smart pointers or you need to bring up a concept of ownership for your myClass instances created with new.
The latter could be:
Instances aof myClass are owned by another instance of myClass (lets call it owner) where &a appears in owner.map (You are doing this already).
Whenever an instance owner becomes destroyed, it has to free all instances it (directly) owns:
~myClass() {
for(const auto& pair : map){
delete pair.second;
}
}

Your Trie::clear() method deletes the same Trie twice.
~Trie() {
clear(map);
}
void clear(unordered_map<char, Trie*> map) {
for (auto& pair : map) {
if (pair.second != nullptr) {
clear(pair.second->map);
}
delete pair.second;
}
}
The destructor ~Trie calls clear(pair.second->map) and then calls delete pair.second which is the same as clear(pair.second->map) again since delete calls the destructor of the pointed-at data. Calling clear() twice on the same map means that the second call is trying to delete already deleted data, which causes the crash. Calling delete on a pointer does not change the value of the pointer, which is why the nullptr check does nothing.
Since the destructor calls clear(), the clear() method does not need to explicitly call itself recursively. Just delete the map pointers.
~Trie() {
clear(map);
}
void clear(unordered_map<char, Trie*> map) {
for (auto& pair : map) {
delete pair.second;
}
}
By the way, calling delete nullptr is fine since it is required to do nothing.

Related

Taking the memory address of vector elements

I need a cache of allocated objects that I could reuse like a free list of objects. Is anything wrong with my approach using a vector?
template <class T>
class Cache
{
private:
vector<T> objects;
vector<T *> freelist;
public:
Cache(int max_size) : objects(max_size)
{
for (int i = 0; i < objects.size(); ++i)
{
freelist.push_back(&objects[i]);
}
}
public
T *GetFree()
{
T *retval = nullptr;
if (freelist.size() > 0)
{
retval = freelist[freelist.size() - 1];
freelist.pop_back();
}
return retval;
}
public
void Release(T *ptr)
{
freelist.push_back(ptr);
}
};
Does this work?

C++ - iteration over a n-ary tree

This is the function with iteration algorithm over a n-ary tree, given a name, and use it to find the parent tree, return parent tree's data if found, "ZERO" if no parent is found, and "NA" if the name is not in any tree in the Tree<string>* vector. It works most of the time, but will occasionally give wrong output that "ZERO", which a parent was supposed to be found, mostly in the leaves.
string getSource(const string name) const { // no recursion
if (existInVector(name, trees)) { // vector of Tree<string>*
queue<Tree<string>> treesQueue;
vector<Tree<string>*>::const_iterator it = trees.begin();
for (; it != trees.end(); ++it) { // for each tree
treesQueue.push(**it); // push tree
for (int i = 0; i < (**it).root->numChildren; ++i) // push children
treesQueue.push((**it).root->children[i]);
while (!treesQueue.empty()) {
Tree<string> temp = treesQueue.front(); // pop front
treesQueue.pop();
for (int i = 0; i < temp.root->childCount; ++i) { // check
if (temp.root->children[i].root->data == name)
return temp.root->data;
}
}
if (it == trees.end()-1 && treesQueue.empty())
return "ZERO";
}
}
return "NA";
}
Here is the class template of the tree:
template <class T>
class Tree {
private:
Node<T>* root;
public:
// ... member functions ...
};
template <class T>
class Node {
private:
T data;
int numChildren;
Tree<T>* children; // Tree<T> array
};
What is the possible reason to get the wrong result sometimes?
// example with wrong result
Tree<string> tree; // below is what is inside, root is Node "G", "H" is child of "G" and so on
G
\-H
\-I
\-J
tree.getSource("J") == "ZERO"; // Supposed to be "I"
You should push children of current node/tree you visit.
I also remove some copies.
std::string getSource(const std::string& name) const {
if (!existInVector(name, trees)) { // vector of Tree<string>*
return "NA";
}
std::queue<const Tree<std::string>*> treesQueue;
for (const auto& tree : trees) {
treesQueue.push(&tree);
while (!treesQueue.empty()) {
const auto& current = *treesQueue.front();
treesQueue.pop();
for (int i = 0; i != current.root->childCount; ++i) {
const auto& child = current.root->children[i];
if (child.root->data == name)
return current.root->data;
treesQueue.push(&child);
}
}
}
return "ZERO";
}

Why the elements disappear after I use push_back() function of vector

I am trying to use std::vector in a class to realize a muti-way tree.
Each time when I want to add a child in on of the member, I use a function addMember. I'm using VS2017 to debug this program. In this function scope the parent's children vector has actually add the elements by push_back(), but after exiting the function, the address of vector will change and the elements I have added will disappear.
Here's my code:
#include <iostream>
#include<string>
#include<vector>
using namespace std;
class member {
public:
string name;
member* parent;
vector<member*> children;
member(string m_name,member* m_parent):name(m_name),parent(m_parent){}
};
class familyTree {
private:
member ancestor;
public:
member* getAncestor() { return &ancestor; }
familyTree(member& m_ancestor):ancestor(m_ancestor){}
member* searchMember(string name,member* node,bool& flag);
void addMember(string name, int children_number,vector<string>& children_name);
};
member* familyTree::searchMember(string name, member* node,bool& flag) {
member* find = NULL;
if (node) {
if (node->name == name)
find = node;
else {
if (!flag) {
for (auto iter = node->children.begin(); iter != node->children.end(); iter++) {
find = searchMember(name, *iter, flag);
if (flag)
break;
}
}
}
}
return find;
}
void familyTree::addMember(string name,int children_number,vector<string>& children_name) {
bool flag = false;
member* parent = searchMember(name, getAncestor(), flag);
for (auto i : children_name) {
member* child = new member(i,parent);
parent->children.push_back(child);
}
}
I suspect that there is something wrong with the familyTree::searchMember function. Here was what you posted:
member* familyTree::searchMember(string name, member* node, bool& flag) {
member* find = NULL;
if (node) {
if (node->name == name)
find = node;
else {
if (!flag) {
for (auto iter = node->children.begin(); iter != node->children.end(); iter++) {
find = searchMember(name, *iter, flag);
if (flag)
break;
}
}
}
}
return find;
}
Notice that there was no method to set the flag = true once you have found the correct node.
The 2nd if statement should be:
if (node->name == name) {
find = node;
flag = true;
}
Otherwise within your for loop,
for (auto iter = node->children.begin(); iter != node->children.end(); iter++) {
find = searchMember(name, *iter, flag);
if (flag)
break;
}
even if there was a successful search, the for loop does not break and so it continues on, and the next child you search is guaranteed to not be a match.
Note that the way your searchMember function is structured results in NULL being returned if you search through a node that does not have a matching name and does not have any children because the for loop is skipped (no children to iterate through). So you end up with a lot of NULL pointers being assigned to parent in addMember.

std::list erasing (free memory)

struct SomeStruct
{
};
class C
{
public:
C()
{
for (int i = 0; i < 100; ++i)
{
m_List.push_back(new SomeStruct);
}
}
private:
std::list<SomeStruct*> m_List;
};
Which of two variants of destructor faster (why?) for freeing memory:
~C()
{
for (auto iter = m_List.begin(); iter != m_List.end(); ++iter)
{
delete *iter;
}
}
~C()
{
while (m_List.size() != 0)
{
delete *m_List.begin();
m_List.pop_front();
}
}
First one is faster. Second one is deleting the head and removing it as well. You don't need to remove the list elements explicitly. The complete list is anyway be destroyed as it is member of C

Returning constructor-less object as output parameter

I want to return an object from a function as an output parameter, but the object has no default constructor so I can't do this:
bool FindFlaggedObject(MyObject& myObject)
{
std::vector<MyObject> myObjects = GetSomeObjectList();
for (UINT i = 0; i < myObjects.size(); i++)
{
if (myObjects[i].Flag) {
myObject = myObjects[i];
return true;
}
}
return false;
}
void main()
{
MyObject myObject; // NOT ALLOWED - OBJECT HAS NO DEFAULT CONSTRUCTOR
if (FindFlaggedObject(myObject))
{
...
}
}
So, it looks like I should return it on the heap and manage it with a shared_ptr instance, like this:
bool FindFlaggedObject(MyObject& myObject)
{
std::vector<MyObject> myObjects = GetSomeObjectList();
for (UINT i = 0; i < myObjects.size(); i++)
{
if (myObjects[i].Flag) {
myObject = new MyObject(myObjects[i]);
return true;
}
}
return false;
}
void main()
{
MyObject* myObjectPtr;
if (FindFlaggedObject(myObjectPtr))
{
std::shared_ptr<MyObject> myObject(myObjectPtr);
...
}
}
The downside is that anyone calling the method will have to remember that he is responsible for deallocating the object.
What is the best practice for returning constructor-less objects as output parameters?
Return by value is almost always the best solution if the object
supports copy (and objects which will be declared on the stack should
generally support copy). If the function can fail, and not always
return an object, you can use some sort of Fallible or Maybe class:
Fallible<MyObject>
FindFlaggedObject()
{
std::vector<MyObject> objects = GetSomeObjectList();
std::vector<MyObject>::const_iterator current = objects.begin();
while ( current != objects.end() && !current->flag ) {
++ current;
}
return current == objects.end()
? Fallible<MyObject>()
: Fallible<MyObject>( *current );
}
You might reflect, though: if GetSomeObjectList() can always return a
reference to an existing list (rather than constructing a list
internally), and you modify it to return a const reference, you could
just return a pointer:
MyObject const*
FindFlaggedObject()
{
std::vector<MyObject> const& objects = GetSomeObjectList();
std::vector<MyObject>::const_iterator current = objects.begin();
while ( current != objects.end() && !current->flag ) {
++ current;
}
return current == objects.end()
? NULL
: &*current;
}
This is a very typical C++ idiom.
Instead of returning a bool and passing in a reference have the function return a smart pointer, ensuring the caller cannot forget to deallocate:
std::shared_ptr<MyObject> myObjectPtr = FindFlaggedObject();
if (myObjectPtr)
{
// Found flagged object.
}
std::shared_ptr<MyObject> FindFlaggedObject()
{
MyObject* result = nullptr;
std::vector<MyObject> myObjects = GetSomeObjectList();
for (UINT i = 0; i < myObjects.size(); i++)
{
if (myObjects[i].Flag) {
result = new MyObject(myObjects[i]);
break;
}
}
return std::shared_ptr<MyObject>(result);
}
Instead of using an out parameter, return a value. Since the value is optional, as indicated by the current return type of bool, you can use boost::optional for that purpose:
boost::optional<MyObject> FindFlaggedObject()
{
std::vector<MyObject> myObjects = GetSomeObjectList();
for (UINT i = 0; i < myObjects.size(); i++)
{
if (myObjects[i].Flag) {
return myObjects[i];
}
}
return boost::none;
}
No need to construct an automatic object with an default constructor.
Just pass constructor parameters.
void main()
{
MyObject myObject (12);
if (FindFlaggedObject(myObject))
{
...
}
}
On the other side, why don't do it this way?
MyObject FindFlaggedObject()
{
std::vector<MyObject> myObjects = GetSomeObjectList();
for (UINT i = 0; i < myObjects.size(); i++)
{
if (myObjects[i].Flag) {
return myObjects[i];
}
}
return 0;
}
void main()
{
MyObject* res = FindFlaggedObject();
if (res != 0) {
...
}
}
You don't have to care to delete res as long res is still member in GetSomeObjectList