I have a problem with creating base class for DoubleLinkedList.
Right now it's giving me this error
/tmp/cc3lORia.o:(.rodata._ZTV24AbstractDoubleLinkedListIiE[_ZTV24AbstractDoubleLinkedListIiE]+0x10):
undefined reference to
`AbstractDoubleLinkedList::createNewNode(int)' collect2: error:
ld returned 1 exit status
I've tried this and that as you can see by commented lines in code, but none of it works.
So how to define abstract template class with abstract method (factory method by the way) and then redefine it in children classes?
/*
* AbstractDoubleLinkedList.hpp
*
* Created on: Mar 2, 2015
* Author: michael
*/
#ifndef ABSTRACTDOUBLELINKEDLIST_H_
#define ABSTRACTDOUBLELINKEDLIST_H_
#include <vector>
using namespace std;
template <class T> class ListNode {
private:
void init();
public:
ListNode();
ListNode(T value);
ListNode *previous;
ListNode *next;
T value;
};
template <class T> void ListNode<T>::init() {
previous = nullptr;
next = nullptr;
}
template <class T> ListNode<T>::ListNode() {
init();
}
template <class T> ListNode<T>::ListNode(T value) {
init();
this->value = value;
}
template <class T> class AbstractDoubleLinkedList {
private:
void pullOutNode(ListNode<T> *node);
protected:
virtual ListNode<T>* createNewNode(T element);
public:
AbstractDoubleLinkedList();
void push_back(T element);
T front();
T back();
void insertBefore(ListNode<T> *node, ListNode<T> *beforeNode);
void insertAfter(ListNode<T> *node, ListNode<T> *afterNode);
void moveNodeAfter(ListNode<T> *node, ListNode<T> *afterNode);
vector<T> toVector();
ListNode<T> *frontNode;
ListNode<T> *backNode;
};
template <class T> void AbstractDoubleLinkedList<T>::push_back(T element) {
ListNode<T>* node = createNewNode(element);
node->previous = backNode;
if (backNode != nullptr) {
backNode->next = node;
node->previous = backNode;
}
else {
frontNode = node;
}
backNode = node;
}
template <class T> void AbstractDoubleLinkedList<T>::pullOutNode(ListNode<T> *node) {
if (node != frontNode) {
node->previous->next = node->next;
}
else {
frontNode = node->next;
}
if (node != backNode) {
node->next->previous = node->previous;
}
else {
backNode = node->previous;
}
}
template <class T> T AbstractDoubleLinkedList<T>::front() {
return frontNode->value;
}
template <class T> T AbstractDoubleLinkedList<T>::back() {
return backNode->value;
}
template <class T> void AbstractDoubleLinkedList<T>::insertAfter(ListNode<T> *node, ListNode<T> *afterNode) {
node->previous = afterNode;
node->next = afterNode->next;
afterNode->next = node;
if (afterNode == backNode) {
backNode = node;
}
}
template <class T> void AbstractDoubleLinkedList<T>::insertBefore(ListNode<T> *node, ListNode<T> *beforeNode) {
node->next = beforeNode;
beforeNode->previous->next = node;
beforeNode->previous = node;
if (beforeNode == frontNode) {
frontNode = node;
}
}
template <class T> void AbstractDoubleLinkedList<T>::moveNodeAfter(ListNode<T> *node, ListNode<T> *afterNode) {
pullOutNode(node);
node->previous = afterNode;
node->next = afterNode->next;
if (node->next == nullptr) {
backNode = node;
}
afterNode->next = node;
}
template <class T> vector<T> AbstractDoubleLinkedList<T>::toVector() {
ListNode<T>* node = frontNode;
vector<int> listAsVector;
bool shouldHaveAnother = (frontNode != nullptr);
while(shouldHaveAnother) {
listAsVector.push_back(node->value);
if (node->next != nullptr)
node = node->next;
else {
shouldHaveAnother = false;
}
}
return listAsVector;
}
template <class T> AbstractDoubleLinkedList<T>::AbstractDoubleLinkedList() {
frontNode = nullptr;
backNode = nullptr;
}
#endif /* ABSTRACTDOUBLELINKEDLIST_HPP_ */
/*
* DoubleLinkedList.hpp
*
* Created on: Feb 26, 2015
* Author: michael
*/
#ifndef DOUBLELINKEDLIST_HPP_
#define DOUBLELINKEDLIST_HPP_
#include "AbstractDoubleLinkedList.hpp"
template <class T> class DoubleLinkedList : public AbstractDoubleLinkedList<T> {
protected:
ListNode<T>* createNewNode(T element) {
return new ListNode<T>(element);
}
public:
~DoubleLinkedList() {
ListNode<T>* node = this->backNode;
bool shouldHaveAnother = (node != nullptr);
while(shouldHaveAnother) {
ListNode<T>* ptr = node->previous;
delete node;
if (ptr != nullptr)
node = ptr;
else {
shouldHaveAnother = false;
}
}
};
};
//template <class T> ListNode<T> DoubleLinkedList<T>::createNewNode(T element) {
// return new ListNode<T>(element);
//}
//template <class T> DoubleLinkedList<T>::~DoubleLinkedList() {
//
// ListNode<T>* node = this->backNode;
// bool shouldHaveAnother = (node != nullptr);
// while(shouldHaveAnother) {
// ListNode<T>* ptr = node->previous;
// delete node;
// if (ptr != nullptr)
// node = ptr;
// else {
// shouldHaveAnother = false;
// }
// }
//}
#endif /* DOUBLELINKEDLIST_HPP_ */
EDIT1:
So, there is a question "Why do I need my own container class and why not use list or vector?"
I need a data structure with constant time random access and constant time deletion and insertion. BUT I've already tried std::unordered_set and It's not good enough (while technically it meets the requirements) because of allocations and deallocations of memory (when deleting and inserting)
So I figured another way. I want to use a linked list with one "guard" element and the end. When I need to "delete" element from it I would move it after guard. And to check if list is "empty" I would check if the first element is the guard element. But I need a constant-time random access. This can be achieved by map of pointers to every element.
But to achieve maximum performance I need to also minimize cache misses. And I thinks that std::list would be scattered across the memory, because it is the normal behaviour for it. So I figured that the only way to do so - is to allocate vector> and then use this preallocated nodes to new elements.
So am I wrong somewhere? Can I achieve maximum performance more easier?
Related
I am trying to make a Generic Linked list in C++ using templates. But i am getting this error 'GenericNode::{ctor}': constructors not allowed a return type through which i can't possibly know what am i doing wrong?
PS. i have also gone through other posts here on Stack Overflow which says that the error is due to the missing semi-colon after the class definition but i think i don't have a 'missing semi-colon' case. Any help?
Code :
GenericLinkedList.h :
#pragma once
template <typename Datatype>
class GenericNode {
Datatype T;
GenericNode *next;
public:
GenericNode() {}
GenericNode(Datatype T);
};
template<typename Datatype>
void GenericNode<Datatype>::GenericNode(Datatype data) {
T = data;
}
template <typename Datatype>
class GenericLinkedList {
GenericNode *Data;
public:
GenericLinkedList() {
Data = NULL;
}
int isEmpty();
void addDataAtFront(Datatype data);
void addDataAtEnd(Datatype data);
void print();
};
template <typename Datatype>
int GenericLinkedList<Datatype>::isEmpty() {
return Data == NULL;
}
template <typename Datatype>
void GenericLinkedList<Datatype>::addDataAtFront(Datatype data) {
GenericNode *newNode, *tmpNode;
newNode = new Node;
newNode->T = data;
newNode->next = NULL;
if (Data == NULL) {
Data = newNode;
}
else {
tmpNode = Data;
Data = newNode;
Data->next = tmpNode;
}
}
template <typename Datatype>
void GenericLinkedList<Datatype>::addDataAtEnd(Datatype data) {
GenericNode *newNode, *tmpNode;
newNode = new Node;
newNode->T = data;
newNode->next = NULL;
if (Data == NULL) {
Data = newNode;
}
else {
tmpNode = Data;
while (tmpNode->next != NULL) {
tmpNode = tmpNode->next;
}
tmpNode->next = newNode;
}
}
template <typename Datatype>
void GenericLinkedList<Datatype>::print() {
GenericNode tmpNode;
tmpNode = Data;
for (tmpNode;tmpNode != NULL;tmpNode = tmpNode->next) {
cout << tmpNode->T << " ";
}
}
.cpp :
#include <iostream>
#include <conio.h>
#include "GenericLinkedList.h"
using namespace std;
int main() {
GenericLinkedList<int> T;
T.addDataAtFront(5);
T.addDataAtEnd(6);
T.addDataAtFront(4);
T.print();
_getch();
}
template<typename Datatype>
void GenericNode<Datatype>::GenericNode(Datatype data) {
T = data;
}
You write the return type void. It's a constructor.
void GenericNode::GenericNode(Datatype data)
remove void its a constructor. Constructors don't return and dont have a return type.
I am attempting to make a queue in c++ using a double linked list. I Have not fully tested everything since i am stuck at the step where you dequeue. I attempted to create a temp node, and move around stuff so when I call delete on the head node in the queue (called queue), and then set the head to a temp node which is the next element, (you can see in the code) but when I call delete, is where it crashes, according to MS Visual studios 2013. Also to add how weird this is, following the stack called, after delete is called, setPrev is called and set the prev node and crashes there. Now I never call this function during any of my destructors deletes so any help will do. I will try my best to understand any answers but I am still new to c++ terminology. Below is my code. Oh one last thing, in main, all I did was call enqueue once, then dequeue once, then delete
Node Class
...
#ifndef TSDNODE_H
#define TSDNODE_H
template <class T>
class DNode
{
private:
DNode<T>* next;
DNode<T>* prev;
T data;
public:
DNode(T);
void setNext(DNode<T>* next);
void setPrev(DNode<T>* prev);
DNode<T>* getNext() const;
DNode<T>* getPrev() const;
T getData() const;
void setData(T data);
~DNode();
};
template <class T>
DNode<T>::DNode(T data)
{
this->next = nullptr;
this->data = data;
this->prev = nullptr;
}
template <class T>
void DNode<T>::setNext(DNode<T>* next)
{
this->next = next;
}
template <class T>
void DNode<T>::setPrev(DNode<T>* prev)
{
this->prev = prev;
}
template <class T>
DNode<T>* DNode<T>::getNext() const
{
return this->next;
}
template <class T>
DNode<T>* DNode<T>::getPrev() const
{
return this->prev;
}
template <class T>
T DNode<T>::getData() const
{
return this->data;
}
template <class T>
void DNode<T>::setData(T data)
{
this->data = data;
}
template <class T>
DNode<T>::~DNode()
{
delete this->next;
delete this->prev;
this->next = nullptr;
this->prev = nullptr;
}
#endif /* TSDNODE_H */
....
Queue Class
....
#ifndef TSQUEUE_H
#define TSQUEUE_H
#include "TSDNode.h"
#include <string>
template <class T>
class Queue
{
private:
DNode<T>* queue;
DNode<T>* tail;
int size;
public:
Queue();
void enqueue(T data);
T dequeue();
~Queue();
};
template <class T>
Queue<T>::Queue()
{
this->queue = nullptr;
this->tail = this->queue;
size = 0;
}
template <class T>
void Queue<T>::enqueue(T data)
{
if (this->tail != NULL)
{
this->tail->setNext(new DNode<T>(data));
this->tail->getNext()->setPrev(this->tail);
this->tail = this->tail->getNext();
}
else
{
this->queue = new DNode<T>(data);
this->tail = this->queue;
}
size++;
}
template <class T>
T Queue<T>::dequeue()
{
T data;
if (this->queue == nullptr)
{
delete this->tail;
delete this->queue;
this->tail = nullptr;
std::string ex = "Exception: Empty Queue\n";
throw ex;
}
else if (this->queue != nullptr)
{
data = this->queue->getData();
DNode<T>* node = this->queue->getNext();
this->queue->setNext(nullptr);
this->queue->setPrev(nullptr);
node->setPrev(nullptr);
//--------------------------------------------------- crashes here
delete this->queue;
this->queue = node;
}
size--;
return data;
}
template <class T>
Queue<T>::~Queue()
{
delete this->queue;
this->queue = nullptr;
this->tail = nullptr;
}
#endif /* TSQUEUE_H */
In your DNode destructor, you don't want to delete the next and prev nodes. You only want to delete this node, not everything it links to.
Remove these lines
delete this->next;
delete this->prev;
Edit: Actually this isn't your problem, because you are clearing out the next and prev values before you delete the node. I still think it is better to not automatically delete the whole chain, but as long as you are consistent with how you handle node deletion it should still work.
You actually problem is that when you dequeue the last node, you still try to set the next pointer of the next node in this line:
node->setPrev(nullptr);
//--------------------------------------------------- crashes here
At this point node is nullptr, so trying to access node->next causes a crash. A simple if test is all you need
if (node != nullptr)
node->setPrev(nullptr);
//--------------------------------------------------- no longer crashes here
Edit 2:
Also note that in the case where the next node in the queue is nullptr, you also want to set the tail to nullptr.
I'm been having trouble with either my constructor or my insert function, I'm not sure which is the issue, but the real issue is that I get the error code mentioning I'm having an error with things getting de-referenced. All I'm trying to do is insert a node containing an integer value in the correct position.
This is the declaration:
template <class T>
class LinkedList
{
template <class T>
struct Node
{
T mData;
Node<T> *mNext;
/* Pre: None
* Post: This object is initialized using default values
* Purpose: To initialize date object
*************************************************************************/
Node()
{
mData = T();
mNext = NULL;
}
/* Pre: None
* Post: This object is initialized using specified data
* Purpose: To intialize date object
*************************************************************************/
Node(T data, Node<T>* next)
{
mData = data;
mNext = next;
}
};
private:
Node<T> *mHead;
int mCount;
public:
LinkedList();
~LinkedList();
int getCount();
T getData(int index);
void setData(int index, T data);
void clear();
void display();
bool insert(T data);
bool isEmpty();
bool isExist(T searchKey);
bool remove(T searchKey);
T removeAt(int index);
T operator[](int index);
void operator=(LinkedList<T> *list);
};
And this is the insert:
template <class T>
bool LinkedList<T>::insert(T data)
{
Node<T>* current = mHead;
if (!current)
{
if (mCount == 0)
{
current->mData = data;
}
else
{
while (current->mNext != NULL)
{
if (current->mData == data)
return false;
else if (current->mNext->mData < data)
{
Node<T>* newNode = new Node<T>();
newNode->mData = data;
newNode->mNext = current->mNext;
current->mNext = newNode;
}
current = current->mNext;
}
}
}
else
{
Node<T>* node = new Node<T>(data, NULL);
current->mNext = node;
}
mCount++;
return true;
}
Every time my program breaks, it's at this line
current->mData = data;
You shouldn't declare Node class as template, in fact you should get a compile error message like error: declaration of 'T' shadows template parameter.
Remove template<class T> from Node and change Node<T> to Node throughout the code.
So I am trying to create my own implementation file which contains instructions for a Queue. I decided to use a linked list to implement the Queue class, meaning that I need to use my own Node struct. Unfortunately, I am stuck and don't know how to properly include this within the file.
This is what I have so far:
#include <string>
#ifndef NODE
template <class DataType>
struct Node
{
DataType data;
Node *next;
};
#endif
template <class DataType>
class Queue
{
public:
Queue();
bool isEmpty() const;
void push(const DataType& parameter);
bool peek(DataType& parameter) const;
bool pop(DataType& parameter);
void makeEmpty();
private:
Node<DataType>* front;
Node<DataType>* end;
};
template <class DataType>
Queue<DataType>::Queue()
: front(0), end(0)
{
}
template <class DataType>
bool Queue<DataType>::isEmpty() const {return 0 == front;}
template <class DataType>
void Queue<DataType>::push(const DataType& parameter)
{
Node<DataType>* node = new Node<DataType>;
node->data = parameter;
node->next = 0;
if (end) end->next = node;
else front = node;
end = node;
}
template <class DataType>
bool Queue<DataType>::peek(DataType& parameter) const
{
if (0 == front) return false; // failed
parameter = front->data;
return true; // success
}
template <class DataType>
bool Queue<DataType>::pop(DataType& parameter)
{
if (0 == front) return false; // failed
parameter = front->data;
Node<DataType>* p = front->next;
delete front;
front = p;
if (front == 0) end = 0;
return true; // success
}
template <class DataType>
void Queue<DataType>::makeEmpty()
{
end = 0;
Node<DataType>* p;
while (front)
{
p = front->next;
delete front;
front = p;
}
}
I'm not sure if I am enclosing the struct by the #ifndef correctly (i'm not even sure if this is the route I should be taking :/), should I be doing something similar to this or should I be doing something else with the code for the struct?
You can just drop the #ifdef/#endif entirely
This is a class template and it may occur many times in several tranlation units, as long as all the occurrences are identical (One Definition Rule)
Alternative
Since Node<> is purely a private concern, I'd make it a nested struct.
Here's a little demo making this more 'modern C++' style.
Edit Thanks to #R.MartinhoFernandes for showing a few more improvements and for reviewing this.
#include <memory>
template <typename T>
struct Queue {
Queue() : front(), end(/*nullptr*/) {}
// Copy-And-Swap idiom
// see http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Copy-and-swap
// or http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
void swap(Queue& q) noexcept {
using std::swap;
swap(q.front, front);
swap(q.end, end);
}
Queue(Queue const& q) : front(), end() {
for(auto it=q.front.get(); it; it=it->next.get())
push(it->data);
}
Queue& operator=(Queue q) {
std::swap(*this, q);
return *this;
}
// end Copy-and-swap
// prevent stack overflows in ~Node if the list grows large (say >1k elements)
~Queue() { clear(); }
bool isEmpty() const {
return !front;
}
void push(T const& data) {
Ptr node(new Node(data));
if (end)
end->next = std::move(node);
else
front = std::move(node);
end = node.get();
}
bool peek(T& data) const {
if(front) data = front->data;
return front.get();
}
bool pop(T& data) {
if(!front) return false;
data = front->data;
front = std::move(front->next);
if(!front) end = nullptr;
return true;
}
void clear() {
end = nullptr;
while(front) front = std::move(front->next);
}
private:
struct Node;
typedef std::unique_ptr<struct Node> Ptr;
struct Node {
Node(T data) : data(std::move(data)), next() {}
T data;
Ptr next;
};
Ptr front;
Node* end;
};
#include <iostream>
int main(int argc, const char *argv[]) {
Queue<int> test;
test.push(1);
test.push(2);
test.push(3);
test.push(5);
test.clear();
test.push(32028);
test.push(10842);
test.push(1839);
test.push(23493);
test.push(9857);
int x;
test.peek(x);
while(test.pop(x)) {
std::cout << x << '\n';
}
}
Note: Perhaps the code in push has been golfed a bit too far, but hey, it shows you how modern C++ requires much less handholding (even without std::make_unique).
Note how I think Clang correctly handles the following version (i.e. with implicit std::move):
void push(const DataType& parameter) {
end = ((end? end->next : front) = Ptr(new Node(parameter))).get();
}
I'm not quite sure why gcc rejects it.
I've been working on an assignment and now I'm stuck with buggy destructors. I have to create a generic binary tree with all the usual member functions and some special operators. There's also a restriction: everything must work iteratively so no nasty recursive hacks this time.
There is obviously something very wrong with the destructor of BinTreeNode class because if I delete the node like this:
BinTreeNode<int> * node = new BinTreeNode<int>();
delete node;
I can still access its data:
node->getData(); //should fail miserably
so deletion has no effect but I have no usable idea how I should correct the destructor.
It seems to me that the algorithm should be about right so I suspect there's something wrong with how I use pointers but at this point I'm so confused that I don't even understand my own code.
Code I have this far:
BinTree.h
#ifndef BINTREE_H_
#define BINTREE_H_
#ifndef NULL
#define NULL 0
#endif
#include "BinTreeNode.h"
template <class T>
class BinTree
{
private:
BinTreeNode<T> * root;
public:
//constructors and destructor
BinTree():
root(NULL){}
BinTree(T data):
root(new BinTreeNode<T>(data)){}
~BinTree();
//search
BinTreeNode<T> * search(T data);
//insert
bool insert(T data);
//remove
bool remove(T data);
};
template <class T>
BinTree<T>::~BinTree()
{
delete root;
}
template <class T>
BinTreeNode<T> * BinTree<T>::search(T data)
{
BinTreeNode<T> * node = new BinTreeNode<T>(data);
BinTreeNode<T> * current = root;
while (current != NULL)
{
if (*current == *node)
{
delete node;
return root;
}
else if (*node < *current)
{
current = current->getLeft();
}
else
{
current = current->getRight();
}
}
delete node;
return NULL;
}
template <class T>
bool BinTree<T>::insert(T data)
{
BinTreeNode<T> * node = new BinTreeNode<T>(data);
BinTreeNode<T> * current = root;
while (current != NULL)
{
if (*current == *node)
{
delete node;
return false;
}
else if (*node < *current)
{
if (current->getLeft() == NULL)
{
current->setLeft(node);
return true;
}
else
{
current = current->getLeft();
}
}
else
{
if (current->getRight() == NULL)
{
current->setRight(node);
return true;
}
else
{
current = current->getRight();
}
}
}
return false;
}
#endif
BinTreeNode.h
#ifndef BINTREENODE_H_
#define BINTREENODE_H_
#ifndef NULL
#define NULL 0
#endif
template <class T>
class BinTreeNode
{
private:
T data;
BinTreeNode<T> *left, *right, *parent;
public:
//constructors and destructor
BinTreeNode():
data(NULL), left(NULL), right(NULL), parent(NULL){}
BinTreeNode(T data):
data(data), left(NULL), right(NULL), parent(NULL){}
~BinTreeNode();
//set and get data member
T getData() const;
void setData(T data);
//set and get left and right branches
BinTreeNode<T> * getLeft() const;
BinTreeNode<T> * getRight() const;
void setLeft(BinTreeNode<T> * node);
void setRight(BinTreeNode<T> * node);
//set and get parent
BinTreeNode<T> * getParent() const;
void setParent(BinTreeNode<T> * node);
//comparison operators
bool operator<(const BinTreeNode<T>& node) const;
bool operator>(const BinTreeNode<T>& node) const;
bool operator==(const BinTreeNode<T>& node) const;
};
template <class T>
BinTreeNode<T>::~BinTreeNode()
{
BinTreeNode<T> * current = this;
BinTreeNode<T> * parent = NULL;
while (current != NULL)
{
parent = current->getParent();
if (current->getLeft() == NULL)
current = current->getLeft();
else if (current->getRight() == NULL)
current = current->getRight();
else
{
if (parent->getRight() == current)
parent->setRight(NULL);
else
parent->setLeft(NULL);
current = NULL; // this line (among others) is very suspicious
}
current = parent;
}
}
template <class T>
T BinTreeNode<T>::getData() const
{
return data;
}
template <class T>
void BinTreeNode<T>::setData(T data)
{
this->data = data;
}
template <class T>
BinTreeNode<T> * BinTreeNode<T>::getLeft() const
{
return left;
}
template <class T>
BinTreeNode<T> * BinTreeNode<T>::getRight() const
{
return right;
}
template <class T>
void BinTreeNode<T>::setLeft(BinTreeNode<T> * node)
{
node->setParent(this);
left = node;
}
template <class T>
void BinTreeNode<T>::setRight(BinTreeNode<T> * node)
{
node->setParent(this);
right = node;
}
template <class T>
BinTreeNode<T> * BinTreeNode<T>::getParent() const
{
return parent;
}
template <class T>
void BinTreeNode<T>::setParent(BinTreeNode<T> * node)
{
parent = node;
}
template <class T>
bool BinTreeNode<T>::operator<(const BinTreeNode<T>& node) const
{
return this->data < node.data;
}
template <class T>
bool BinTreeNode<T>::operator>(const BinTreeNode<T>& node) const
{
return this->data > node.data;
}
template <class T>
bool BinTreeNode<T>::operator==(const BinTreeNode<T>& node) const
{
return this->data == node.data;
}
#endif /* BINTREENODE_H_ */
Your BinTreeNode destructor should simply be:
template <class T>
BinTreeNode<T>::~BinTreeNode() {
delete left;
delete right;
}
That will call left and right's destructors recursively, freeing the memory allocated for those nodes and their child nodes. This will as a consequence free the entire tree.
Assigning NULL to a pointer does not free the memory pointed by it.
On the other hand, what you mention, that after deletion, this line:
node->getData();
Still returns data, is perfectly normal. Deletion frees the memory, but the data stored in it might still be available for a while, until something new is written in that memory address. Accessing an already free'd memory address implies undefined behaviour.
BTW, you should use "0"(without quotes) in C++ instead of NULL. Therefore, there it's not necessary to use the #ifndef NULL(...).
EDIT: I hadn't seen the "no recursion" comment. Here's a non-recursive algorithm:
#include <deque>
/* ... */
template <class T>
BinTreeNode<T>::~BinTreeNode() {
std::deque deq;
// we're going to delete our children
deq.push_back(this);
while(deq.size()) {
BinTreeNode<T> *ptr = deq.front();
deq.pop_front();
if(ptr) {
deq.push_back(ptr->left);
deq.push_back(ptr->right);
// we don't want the child nodes
// to double delete the children
ptr->left = 0;
ptr->right = 0;
// avoid deleteing ourselves
if(ptr != this)
delete ptr;
}
}
}
I haven't tested it, but it should work.