How to delete a template? - c++

I'm having trouble with deleting my template.
My template and destructor:
template<class S, class T>
class Consortium
{
private :
map<const S, Node<T>*> m_consortiumMap;
Heap<T>m_consortiumHeap;
public :
~Consortium();
void Insert(const S key, T toAdd);
void Update(const S key);
void Remove(const S key);
const T Top();
};
template<class S, class T>
Consortium<S,T>::~Consortium()
{
m_consortiumMap.clear();
delete &m_consortiumHeap.;
}
My heap and destructor:
template <class T>
class Heap
{
private :
vector<Node<T>*> m_heapVector;
public :
~Heap();
int parent(int i) const {return i / 2;}
int left(int i) const {return 2 * i;}
int right(int i) const {return 2 * i + 1;}
void heapify(int index);
Node<T>* extractMin ();
void heapDecreaseKey (int index, Node<T>* key);
void MinHeapInsert (Node<T>* key);
Node<T>* ExtractNode(int index);
Node<T>* top ()const {return m_heapVector[0];}
};
template<class T>
Heap<T>::~Heap()
{
for (int i = 0 ; i < m_heapVector.size() ; i++)
m_heapVector.erase(m_heapVector.begin() + i);
}
and this is the object that holds the template, I'm having problems with that also:
class Garage
{
private :
Consortium<string, Vehicle*> m_consortium;
public :
~Garage() {delete &m_consortium;}
};
what's wrong here?

This is wrong on its face:
delete &m_consortiumHeap;
You must only delete things that you allocated with new. m_consortiumHeap is part of the class and gets automatically allocated when the class gets allocated and automatically deallocated when the class gets deallocated. You cannot and must not explicitly delete it.
This may have the opposite problem:
m_consortiumMap.clear();
the contents of m_consortiumMap are pointers. I can't tell from the code you've shown, but if the nodes within the map are allocated by the Consortium class using new, they must be deleteed, otherwise you will leak memory. Clearing the map will only get rid of the pointers, it will not deallocate the memory that they point to. You must first iterate through the map and delete each element. While deallocation of the elements is important, clearing the map in the destructor is kind of pointless since the map itself will be destroyed immediately afterwards anyway.
This is just perplexing:
for (int i = 0 ; i < m_heapVector.size() ; i++)
m_heapVector.erase(m_heapVector.begin() + i);
first of all, everything I said about m_consortiumMap applies also to m_heapVector: If the contents were allocated with new by the Heap class, you must delete them in the destructor. And erasing the pointers from the vector is pointless, not to mention that the above loop has a logic error in it. When you iterate over a container, you should use the iterators themselves, e.g.
for (std::vector<Node<T>*>::iterator i = m_heapVector.begin() ; i != m_heapVector.end() ; i++)
Also, std::vector, like std::map, has a clear() function, but like I said it's pointless to clear the vector in the destructor. What you really want to do is deallocate the elements (if necessary).

If you didn't use new to create an object you can't use delete to get rid of it.

You probably want to delete the objects pointed by the elements in the vector. Erase method doesn't do that, it just remove the pointer element from the vector, without destroying the pointed object. So you need (I presume) to delete the pointed object first, to avoid memory leaks. You cold do this:
for( vector<Node<T>*>::iterator iter = m_heapVector.begin(), endI = m_heapVector.end(); iter != endI; ++iter)
{
delete *iter;
}
// m_heapVector.clean(); // Not necessary in destructor, since the vector will be destroyed anyway.
Using C++0x functions:
std::for_each( m_heapVector.begin(), m_heapVector.end(), []( Node<T>* node) { delete node; });
Also, use clear() method of the container (vector in your case) to remove all the elements.

Since m_consortiumHeap is a data member of your class (directly, not a pointer to it), you don't have to explicitly delete it. When the Consortium instance is destructed, it will automatically call the destructor of m_consortiumHeap for you.

Related

how to allocate memory foe generic class without having a T()

I have a class and I want to write a generic sorted list that we can use it with that class:
class A
{
int n;
public:
A(int n):n(n){}
};
and this how I thought to do my sorted list class
template <class T>
class SortedList
{
T* data;
int size;
int max_size;
void expand();
static const int EXPAND_RATE=2;
static const int INITIAL_SIZE=10;
public:
SortedList();
};
template <class T>
SortedList<T>::SortedList():data(new T[INITIAL_SIZE]),size(0),max_size(INITIAL_SIZE){}
// ^^^ here we need a T()
now the problem is that class A doesn't have a c'tor like this A()
does anyone have any Idea how can I write the sortedlist class without needing the A()??
PS: some people have recommended to do Nodes with T data and next but I can't see how can I do this, and how could this help? since we still need a T()
Edit: I tried now to do it this way:
template <class T>
class SortedList
{
T** data;
// ^^
int size;
int max_size;
void expand();
static const int EXPAND_RATE=2;
static const int INITIAL_SIZE=10;
public:
SortedList();
};
template <class T>
SortedList<T>::SortedList():data(new T*[INITIAL_SIZE]),size(0),max_size(INITIAL_SIZE){}
now I am facing a different problem with this function:
void SortedList<T>::insert(const T& object)
{
if(size>=max_size)
{
expand();
}
int index=0;
for(int i=0;i<size;i++)
{
T item=*data[i];
// when I try to print item nothing goes out
if(item<object)
// ^^^ here I get a segmentation fault
{
continue;
}
index=i;
break;
}
size++;
for (int i = size-1; i >index; i--)
{
data[i]=data[i-1];
}
T Item(object);
T* ptr= &Item;
data[index]=ptr;
//when I print *data[index] it does get printed perfectly
}
does anyone have any Idea how can I write the sortedlist class without needing the A()??
Option 1: Allocate memory for each element separately. In other words, use a node based data stucture such as a linked list.
Option 2: Separate allocation of memory from creation of the object. This can be achieved by using std::allocator to allocate the memory, and std::construct_at to create the object (use placement-new instead prior to C++20). This is how dynamic array-like data structures such as std::vector are implemented.
P.S. Manual memory management is challenging. If you attempt to do it without studying the subject in depth, you'll very likely write a broken program.

C++: Copy constructor crashing

I am having trouble coding Copy constructor for C++ HashTable. Now below is the class structure
template <class TYPE>
class HashTable : public Table<TYPE>
{
struct Record
{
TYPE data_;
string key_;
Record* Next;
Record(const string& key, const TYPE& data)
{
key_ = key;
data_ = data;
Next = nullptr;
}
Record(const Record& a) {
if(!a.key_.empty()){
if(a.Next == nullptr){
Next = nullptr;
}
else
{
Record* temp = a.Next ;
Record *temp2 = Next;
while(temp != nullptr)
{
temp2 = temp ;
temp = temp->Next ;
}
temp2->Next = nullptr;
}
data_ = a.data_ ;
key_ = a.data_ ;
} // user-
};
int TableSize;
Record** records;
}
};
and below is the copy constructor
template
HashTable<TYPE>::HashTable(const HashTable<TYPE>& other)
{
records = new Record*[other.TableSize];
TableSize = other.TableSize;
for(int i = 0 ; i < other.TableSize; i++)
records[i]= (new Record(*other.records[i]));
}
I have also posted the code on ideone http://ideone.com/PocMTD. The code for copy constructor seems to be crashing. I don't see any memory leak that will cause the program to crash. I have tried memcopy, using the insert function and the all seems to fail.
Replace int TableSize; and Record** records; with std::vector<std::unique_ptr<Record>>
In Record, change Record* Next; to Record* Next=nullptr;.
Stop calling new.
Include HashTable(HashTable&&)=default;.
HashTable<TYPE>::HashTable(const HashTable<TYPE>& other)
{
records.reserve( other.records.size() );
for (auto const& rec_in : other.records)
records.emplace_back( new Record(*rec_in) ); // make_shared<Record> in C++14
}
Now we are no longer doing manual memory management. So an entire set of worries is gone.
Next, look at that raw Next pointer. It is bad news. When you copy a Record, the Next pointer points into the old set of Record structures.
We can fix this in a few ways. The slickest is to use an offset pointer.
template<class T>
struct offset_ptr {
std::ptrdiff_t offset = std::numeric_limits<std::ptrdiff_t>::max();
explicit operator bool()const {
return offset!=std::numeric_limits<std::ptrdiff_t>::max();
}
T* get() const {
return (T*)( offset+(char*)this );
}
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
operator T*() const { return get(); }
offset_ptr(std::nullptr_t):offset_ptr() {}
explicit offset_ptr(T* p) {
if (!p) return;
offset = (char*)p-(char*)this;
Assert(*this);
}
offset_ptr()=default;
offset_ptr(offset_ptr const&)=default;
offset_ptr& operator=(offset_ptr const&)=default;
offset_ptr(offset_ptr&&)=default;
offset_ptr& operator=(offset_ptr&&)=default;
};
which instead of storing a pointer by absolute location, stores an offset.
Now we do this:
template<class TYPE> struct Table{};
template <class TYPE>
class HashTable :public Table<TYPE>
{
public:
struct Record
{
TYPE data_;
std::string key_;
offset_ptr<Record> Next;
Record(const std::string& key, const TYPE& data)
{
key_ = key;
data_ = data;
Next = nullptr;
}
Record(const Record& a)
{
if(!a.key_.empty())
{
if(a.Next == nullptr)
{
Next = nullptr;
}
else
{
auto temp = a.Next;
while(temp != nullptr)
{
Next = temp;
temp = temp->Next;
}
}
data_ = a.data_;
key_ = a.data_;
}
}
};
std::vector<Record> records;
};
and no copy ctor is needed; the offset ptr knows the location of the other record as an offset within the records. Data is stored by-value instead of by-reference.
Note that we have a vector of Records, not pointers-to-Records. This is key for the offset_ptr to work. Resizing isn't a problem, as the offsets remain the same. Copying remains safe, as offsets on each side now refer to other elements within their vector. Inserting/removing in the middle is dangerous, but simply nulling elements is not.
Note that buffers of size max std::ptrdiff_t or beyond are not supported by the above offset_ptr. On a 64 bit system that is about 2 gigs; on a 64 bit system it is large. (I don't use 0 for the null value, because if I did then an offset_ptr<X> as the first member of a struct X would nullify if I ever made it point to its enclosing X.)
boost also has a less bespoke offset_ptr type. The implementation above is meant as a sketch of how easy it is, not a solid implementation.
You do not show the complete code here (neither on ideone), but let me take a guess based on what I see.
I assume that your other object, which you pass in the copy c'tor has a fully set up list of Records.
I further assume that your HashTable class has a destructor (not shown) which deletes all the linked Records.
Your copy constructor calls the copy c'tor of Record(for each entry in the array of pointers to Record). The Record coyp c'tor only makes a shallow copy, i.e. only the pointer to the next element is copied (it will still point to the next element of the copied Record from the other hash table.
Thus, when other and its copy are deleted (at the end of scope or program; not shown), you will have double deletion (crash).
Fix: Make sure that Record has correct copy constructor, copy assignment and destructor (maybe even move c'tor and move assignment) (rule of five).
The same applies for the HashTable class as well.
Better fix: Use std::unordered_map.

Destructor of a class C with members of pointer C

Assume the following class declaration:
class NTree
{
private:
const T* fKey;
NTree<T, N>* fNodes[N]; // N subtrees of degree N
NTree();
...
}
in which we can add some fNodes, representing a subtree given an index. These will be dynamically allocated using new. However, there are elements which are static, and not dynamically allocated:
public:
static NTree<T, N> NIL; // sentinel
...
We choose to allocate this on the stack using the default constructor supplied above.
template<class T, int N>
NTree<T, N> NTree<T, N>::NIL;
Now, let's say we wish to delete an NTree. The class NTree is recursive, having pointer to NTree inside it.
This is what I'm struggling with.
I understand the logic behind a destructor, if we have e.g.
class MyClass
{
private:
TypeA * myA;
TypeB * myB;
TypeC * myC;
...
}
We could use a destructor to prevent these pointers from dangling, or getting lost.
~MyClass()
{
delete myA;
delete myB;
delete myC;
}
However, when it comes to a recursive class, I have no clue how to wrap my mind around this, how to understand deletion.
A simple thing to think of:
template<class T, int N>
NTree<T, N>::~NTree()
{
delete[] fNodes;
}
However, it won't work, as some nodes are NIL (stack allocated), so deleting them will result in a crash.
Another idea is:
template<class T, int N>
NTree<T, N>::~NTree()
{
for (int i = 0; i < N; i++)
{
delete fNodes[i];
}
}
However, this will result in a stack overflow, because of the stack being bombarded with frames for each recursive call of ~NTree()
And the following:
template<class T, int N>
NTree<T, N>::~NTree()
{
for (int i = 0; i < N; i++)
{
if (fNodes[i] != &NIL)
delete fNodes[i];
}
}
Results in a read exception, because the recursive calls will deallocate fNodes[i] for a particular stack frame, thus trying to access that memory is invalid.
So my question is, how can I delete a member variable, where that member is recursively defined as the same class?
How can I make my destructor work?
Edit: Attempt to provide more information without making it too convoluted
I'm defining a destructor so it's probably wise to show you my copy constructor and assignment operator:
template<class T, int N>
NTree<T, N> & NTree<T, N>::operator=(const NTree & aOtherNTree)
{
//This is an already initialized object.
if (this != &aOtherNTree)
{
fKey = aOtherNTree.fKey;
for (int i = 0; i < N; i++)
{
if (fNodes[i] == &NIL)
continue; //continue if nil
delete fNodes[i]; //important -- so no dangling pointer
fNodes[i] = new NTree<T, N>; //allocate memory
fNodes[i] = aOtherNTree.fNodes[i]; //assign
}
}
return *this;
}
..
template<class T, int N>
NTree<T, N>::NTree(const NTree & aOtherNTree)
{
//This is a new object, nothing is initalized yet.
fKey = aOtherNTree.fKey;
for (int i = 0; i < N; i++)
{
if (fNodes[i] == &NIL)
continue;
fNodes[i] = new NTree<T, N>;
fNodes[i] = aOtherNTree.fNodes[i];
}
}
I hope this shows all instances of when I allocate memory that needs explicit deletion in the destructor.
NIL is a sentinel, we always assign a leaf to NIL.
This part is provided by the professor, it is where we set up the initial objects:
NS3Tree root(A);
root.attachNTree(0, *(new NS3Tree(A1)));
root.attachNTree(1, *(new NS3Tree(A2)));
root.attachNTree(2, *(new NS3Tree(A3)));
root[0].attachNTree(0, *(new NS3Tree(AA1)));
root[1].attachNTree(0, *(new NS3Tree(AB1)));
root[1].attachNTree(1, *(new NS3Tree(AB2)));
A1, A2, etc, are strings
Your copy constructor and assignment operator are both totally wrong.
if (fNodes[i] == &NIL)
continue; //continue if nil
delete fNodes[i]; //important -- so no dangling pointer
This is wrong logic. If your old child value was NIL, it will stay NIL forever, because it will be never assigned. This should be:
if (fNodes[i] != &NIL)
delete fnodes[i];
Of course in the copy ctor the above fragment should not appear, because fNodes[i] doesn't have any determined value. It should only appear in the assignment.
Now
fNodes[i] = new NTree<T, N>; //allocate memory
fNodes[i] = aOtherNTree.fNodes[i]; //assign
You allocate some node and then immediately overwrite a pointer to it with another pointer, managed by another node. The first assignment thus has no effect, except for a memory leak. The second one will result in an error later on. Here's a correct invocation
if (aOtherNTree.fNodes[i] == &NIL)
fNodes[i] = &NIL;
else
fNodes[i] = new NTree<T, N> (*aOtherNTree.fNodes[i]); // make a new copy
An alternative else clause is
else {
fNodes[i] = new NTree<T, N>;
*fNodes[i] = *aOtherNTree.fNodes[i]); // assign the object, not the pointer
}
I recommend writing a debugging function that would print a tree, including the address of each node. While debugging, print every tree you make to ensure no pointer sharing occurs.

C++ -- determine if generic variable is a pointer

I have a class, which I'll refer to as myclass, that has a list container of the type T. I also have a couple of methods that remove items from the list. Should the T be a pointer of some sort, I would like to check that it indeed is a pointer and then delete it in order to relieve allocated resources back to memory. Here's a snippet of code:
template<typename T>
class myclass{
private:
std::list<T> * container;
// other vars
public:
void erase(const T &item){
if (!this->find(item)) // find is defined elsewhere
return false;
auto temp = container->begin();
for (int i = 0; i < container->size(); ++i){
// this is where i would like to check if *temp is a pointer,
// so that I can assign it to a pointer var, remove it from the list,
// then delete the pointer,
//otherwise just simply remove it from the list.
}
}
};
EDIT
auto temp = container->begin();
I want to know how to determine if *temp is a pointer so that I can do the following:
T * var = *temp;
container->remove(temp); // remove or erase, i can't recall at the moment
delete var;
but I only want to do that if *temp is a pointer
1) Determine if Type is a pointer in a template function
2) How would you know if that pointer is pointing to dynamically allocated memory?
I don't think this is a wise idea. You don't know whether the user has provided pointers to data allocated on the stack, or to data that is managed in some other way (eg with smart pointers).
But to answer the question, look at
std::is_pointer<T>::value // in type_traits header
http://en.cppreference.com/w/cpp/types/is_pointer
This is a C++11 feature.
Sorry, but no: std::list<T>::iterator (which is what begin() will return and therefore will be the type of temp) can't ever be a pointer. It must be a type that (at the very least) overloads pre- and post-increment and decrement to do linked list traversal so ++ will do something like pos = pos->next; and -- will to something like pos = pos->prev;.
If you're trying to figure out if *temp (which will be the same type as T) is a pointer, that's a whole different story. You basically have two routes. The one I'd prefer as a general rule would be to provide a specialization of your class for pointers:
template<typename T>
class myclass{
private:
std::list<T> container;
// other vars
public:
void erase(const T &item){
if (!container->find(item)) // find is defined elsewhere
return false;
auto temp = container->begin();
for (int i = 0; i < container->size(); ++i){
container.erase(temp);
}
}
};
template<class T>
class myclass <T *> {
private:
std::list<T> container;
// other vars
public:
void erase(const T &item){
if (!container->find(item)) // find is defined elsewhere
return false;
auto temp = container->begin();
for (int i = 0; i < container->size(); ++i){
delete *temp;
container.erase(temp);
}
}
};
The biggest problem with this is that you may end up duplicating a fair amount between the base template and the specialization for pointers. There are a couple of ways of avoiding that. One is to use a base class that implements the common behavior, then derive the two specializations from that to provide the specialized behavior. Another would be to use some enable_if or SFINAE to enable different versions of the erase function depending on whether the contained type is something that can be dereferenced or not.
As an aside, you probably shouldn't have std::list<T> *container; -- it should probably be just std::list<T> container; (or, better still in most cases, std::vector<T> container;)
Isn't it annoying container's don't delete normal pointers? Well in C++ raw pointers don't actually own the object. There could be many pointers pointing to the same object. You need a unique pointer - stl provides one in c++11. When a unique_ptr is removed from the list, it will destroy the object it points to, so there is no need to complicate erase.
#include <list>
#include <memory>
#include <type_traits>
using namespace std;
template<typename t, bool b>
struct Selector {
typedef list<T> container;
};
template<typename t>
struct Selector<t, true> {
typedef list<unique_ptr<T> > container;
};
template<typename T>
class myclass{
private:
Selector<T, is_pointer<T>::value>::container* container;
// other vars
public:
void erase(const T &item){
if (!this->find(item)) // find is defined elsewhere
return false;
auto temp = container->begin();
for (int i = 0; i < container->size(); ++i){
// removing the unique_ptr delete's pointer
}
}
};

remove a cell from array give me run time error

i have a template array consist Cells that holds the data, described in the code:
template <class T>
class Array
{
private:
//the array is consist cellss that holds the data
template<class S>
class Cell
{
public:
//members:
S* m_data;
//methods:
//C'tor:(inline)
Cell(S* data=NULL): m_data(data){};
//D'tor:(inline)
~Cell(){delete m_data;};
//C.C'tor:(inlnie)
Cell(const Cell<S>& cell): m_data(cell.m_data){};
};
private:
//members of Array:
Cell<T>* m_head,*m_last;
unsigned int m_size;
public:
/*******************C'tors and D'tors************************/
//C'tor:(inline)
Array():m_head(NULL),m_last(NULL), m_size(0){};
//D'tor:
~Array(){delete[] m_head;};
//C.C'tor:
Array(const Array& array): m_head(array.m_head),m_last(array.m_last),m_size(array.m_size){};
/****************Adding********************/
//add an element to the end of the Array:
void add(const T added);
/*******************Returning and deleting***********************/
T& operator[](const unsigned int index)const {return *(m_head[index].m_data);};
//delete the last element:
void remove();
/*********************Size*****************************/
//returning the number of elements:(inline)
const unsigned int size()const{return m_size;};
//check if the Array is empty:
bool isEmpty()const {return (m_size==0);};
};
now this is the implementaion of add:(after tests look like it works fine but just for case i write it here also)
template <class T>void Array<T>::add(const T added)
{
//allocating memory for the new array:
Cell<T>* newarray=new Cell<T>[m_size+1];
//copy all the elements from the old array:
unsigned int i;
for (i=0; i<m_size;i++)
newarray[i].m_data=m_head[i].m_data;
//put the added in the last index:
T* newelement= new T(added);
newarray[i].m_data=newelement;
//change the ptrs:
m_head=newarray;
m_last=&newarray[m_size];
//increase the counter:
m_size++;
}
and this is the implementaion of remove:
template <class T>void Array<T>::remove()
{
//if there is only 1 element:
if(m_size==1)
{
delete[] m_head;
m_head=m_last=NULL;
}
//change the last the previus cell
else
{
delete m_last;
m_last=m_last-1;
}
//and decrease the counter:
m_size--;
}
now when do:
Array<int> a;
a.add(3);//work fine
a.add(4);//work fine
a.remove();//fail
i get a runtime error from the line delete m_last; even though m_last point to a cell that actually hold data (m_last point to a cell holds 4).
what am i missing here? why cant i delete a pointer to a cell in the Array?
the error VS2012 give me:_BLOCK_TYPE_IS_VAILED(pHead->nBlockUse)
another important thing i forgot to say: when debug it doesnt enter the D'tor of Cell at all, it just get out when going to the delete.
You can't delete one element of array.
int *x = new int[10];
delete &x[2] ; // It is incorrect!
You can only delete whole of array:
delete [] x;
The destructor ~Cell calls delete. That's a sure sign that the constructor should call new.