I am playing around with my containers.
In my template class for an container i make a pointer of T* (T* mData;) as a member variable of the container class. This is a pointer to an array type.
In the destructor i call the delete keyword delete mData; or delete[] mData; but all i hear is a ding in the test application and no more output is write to the console.
Can someone please explain what is going on is deleting a member of T* mData; somehow different to deleting everything else? if so can someone please explain I've looked everywhere and can't find an answer.
UPDATE
I read the comments and since people were willing to help in return i have decided to post the this update and answer the question itself. Ps don't laugh it was a silly mistake.
OLD CODE (looked something like this)
template<typename T>
class TestVector {
// members
T* mData;
size_t mSize;
// methods
void AddData(T data){
T* buffer;
memcpy_s(buffer, sizeof(mData), mData, sizeof(mData));
if(!buffer){
// log error
return;
}
mSize++;
SafeDelete(mData); // deleting this here was the problem (check destructor)
mData = new T[mSize];
mData = buffer;
mData[mSize - 1] = data;
}
// constructors
TestVector(void){
mData = new T[0];
ZeroMemory(mData, sizeof(mData);
mSize = 0;
}
~TestVector(void){
SafeDelete(mData); // when deleting the mData member again here the problem would occur, the destructor was called the beep noise would sound and the console window would freeze
}
// operators
};
I will answer what i did to change this as a Answer to the question . . .
I will admit i do not understand why deleting the same pointer of the class more than once gave an error, maybe the memory address of the new pointer wasn't know to the class so the destructor couldn't find it but to solve the issue i went with old school C.
template<typename T>
class TestVector {
private:
T * mData;
size_t mSize = 0;
public:
TestVector(void) {
mSize = 2;
mData = (T*)malloc(mSize * sizeof(T));
for (int i = 0; i < mSize; i++) {
mData[i] = i;
}
cout << "Values in t1 are: " << mData[0] << ", " << mData[1] << endl;
}
~TestVector(void) {
free(mData); // only place the pointer is ever deleted
}
public:
void AddData(T data) {
mSize++;
T* newData = (T*)realloc(mData, mSize * sizeof(T));
mData = newData;
mData[mSize - 1] = data;
for (int i = 0; i < mSize; i++) {
cout << "Value: " << i << " is equal to: " << mData[i] << endl;
}
}
};
I just used malloc() to allocate, realloc() to reallocate a bigger array to the pointer and free() to release the pointer.
I could of just omitted the SafeDelete(mData); in the first version and just called new over the top i think but i actually prefer using old school C for this type of thing, it makes more sense :)
Related
Hello I have a bit ambiguity about writing a proper destructor:
class SLLst
{
public:
SLLst() = default;
SLLst(const SLLst&);
SLLst& operator=(SLLst);
~SLLst();
void insert(int);
void remove(int);
private:
SLLst* next = nullptr;
int data = 0;
friend void swap(SLLst&, SLLst&);
friend std::ostream& print(std::ostream&, const SLLst&);
};
SLLst::SLLst(const SLLst& rhs) :
next(rhs.next ? new SLLst() : nullptr),
data(rhs.data)
{
cout << "cpy-ctor" << endl;
}
SLLst& SLLst::operator=(SLLst rhs)
{
cout << "operator=(SLLst)" << endl;
using std::swap;
swap(*this, rhs);
return *this;
}
void swap(SLLst& lhs, SLLst& rhs)
{
cout << "operator=(SLLst)" << endl;
using std::swap;
swap(lhs.next, rhs.next);
swap(lhs.data, rhs.data);
}
SLLst::~SLLst()
{
cout << "dtor" << endl;
delete next;// is this enough?
// or should I use this code?
//SLLst* cur = next;
//SLLst* n = nullptr;
//while (cur != NULL) {
// n = cur->next;
// cur->next = nullptr;
// delete cur;
// cur = n;
//}
}
void SLLst::insert(int x)
{
SLLst* tmp = new SLLst();
tmp->data = x;
if (!next)
{
next = tmp;
return;
}
tmp->next = next;
next = tmp;
}
std::ostream& print(std::ostream& out, const SLLst& lst)
{
auto tmp = lst.next;
while (tmp)
{
out << tmp->data << ", ";
tmp = tmp->next;
}
return out;
}
As you can see if I just use delete next; in destructor then I get it called as many as nodes in the list but why many implementations use a loop to free the nodes like the commented code in destructor?
Because if I only call delete on next then the destructor will be called recursively thus I think I don't need a loop to free the nodes in destructor? is it correct?
When should I use a loop to free nodes in destructor? Thank you!
*If I run my code I'll get:
81, 77, 57, 23, 16, 7, 5,
done
dtor
dtor
dtor
dtor
dtor
dtor
dtor
dtor
As you can see dtor is called 8 times; does this mean it has properly freed all the nodes?
As you can see if I just use delete next; in destructor then I get it called as many as nodes in the list
Yep.
Because if I only call delete on next then the destructor will be called recursively thus I think I don't need a loop to free the nodes in destructor? is it correct?
Yep.
When should I use a loop to free nodes in destructor?
When you need to.
but why many implementations use a loop to free the nodes like the commented code in destructor?
Because many implementations are "C-like", and do not use destructors. So they need to.
You are making the most of C++'s object management features to "do the loop for you". Yay!
(Although, to be honest, I would still do it in a loop, because your way is potentially quite stack-heavy.)
Now go one step further and switch to std::list (or std::forward_list). 😏
Just immediately off the bat, std::unique_ptr would take care of this for you, but if you want to do it yourself, then it would look something like this, keep in mind this is a minimal example.
RAII is a very important principle in C++, it basically means, allocate when you need it, but destroy whenever you're done using it.
So if a node is being pointed to, and you delete the node that points to it, then that node should also destroy the thing it points to since it has ownership over it.
class List {
Node* first_node;
~List() {
delete first_node;
}
};
class Node {
~Node() {
delete next; // will then in turn destroy the one it points to untill one is nullptr, deleting nullptr is well defined in C++ nowadays
}
Node* next;
};
Example with std::unique_ptr
class List {
std::unique_ptr<Node> first_node;
// default dtor
};
class Node {
std::unique_ptr<Node> next;
// default dtor
};
So I am trying to resize an array by making a function call ResizeArray(). However, I don't know what is the correct way to use "delete" in this case. (I make a new int * and copy the value from the original to it and then I make the original pointer points to the new one, now I don't know what to "delete"
class Base
{
private:
int sizeInClass;
int *arrayy=nullptr;
public:
Base(int s)
{
sizeInClass=s;
arrayy = new int[s]{};
setValue();
};
void setValue()
{
for(int x=0;x<sizeInClass;x++)
{
arrayy[x]=x;
}
}
void print()
{
int countter=0;
for(int x=0;x<sizeInClass;x++)
{
countter++;
cout<<arrayy[x]<<endl;
}
cout<<"The size of the array is : "<<countter<<endl;
}
void ResizeArray(int newSize)
{
int *newArray = nullptr;
newArray = new int[newSize];
for(int x=0;x<sizeInClass;x++)
{
newArray[x]=arrayy[x];
}
delete [] arrayy; /////////////////////////////////// should i use deleate here ?
arrayy = newArray;
delete [] newArray; /////////////////////////////////// or should I use deleate here ?
sizeInClass = newSize;
}
~Base()
{
delete [] arrayy; /////////////////////////////////// or just use delete here
arrayy=nullptr;
}
};
int main()
{
Base b(5);
b.print();
b.ResizeArray(8);
b.setValue();
b.print();
return 0;
}
The first and the 3rd of your suggested delete are correct.
Regarding handling resources,
for sure you need de-allocation in destructor, to free resources when your container class
is destroyed. When you want to resize contained array, you are handling it in ResizeArray function, so below is basic proposal for it, with clarification comments:
void ResizeArray(int newSize)
{
int *newArray = new int[newSize];
if (nullptr != newArray) { // we take action only if allocation was successful
for(int x=0;x<sizeInClass;x++)
{
newArray[x]=arrayy[x];
}
delete [] arrayy; // good, here you delete/free resources allocate previously for an old array
arrayy = newArray; // good, you redirect member ptr to newly allocated memory
/* delete [] newArray; ups, we have member ptr point to this location
and we cannot delete it, after this, accessing it would be UB,
beside in dtor we would have double, second deletion */
sizeInClass = newSize;
}
}
Your destructor is fine.
There could be further improvements in your code, but this is related to your question.
For an assignment I cannot use a STL list, it must be a custom list. As the title states, I have memory leaks even though I am calling delete on the nodes \ items. I would appreciate any help on this.
List Source
template <typename T>
class DLinkList
{
private:
struct Node
{
T data;
Node *nextNode;
Node *prevNode;
Node(T data, Node *nextNode = nullptr, Node *prevNode = nullptr)
{
this->data = data;
this->nextNode = nextNode;
this->prevNode = prevNode;
}
~Node() { delete data; }
};
Node *head;
Node *tail;
public:
DLinkList();
~DLinkList();
void push_back(T data);
};
template <typename T>
inline void DLinkList<T>::push_back(T data)
{
if (isEmpty())
{
head = new Node(data);
tail = head;
}
else
{
tail->nextNode = new Node(data, nullptr, tail);
tail = tail->nextNode;
}
}
template <typename T>
DLinkList<T>::DLinkList()
{
head = nullptr;
tail = nullptr;
}
template <typename T>
DLinkList<T>::~DLinkList()
{
Node *ptr = head;
while (ptr->nextNode != nullptr)
{
Node *garbage = ptr;
ptr = ptr->nextNode;
delete garbage;
}
}
Foo Class and main
class Foo
{
public:
Foo() { i = 0; d = 0.0; }
Foo(int i, double d) { this->i = i; this->d = d; }
int getInteger() { return i; }
double getDouble() { return d; }
private:
int i;
double d;
};
int main()
{
DLinkList<Foo*> f1;
f1.push_back(new Foo());
f1.push_back(new Foo(2, 5.5));
cout << "1st Values: " << f1.at(0)->getInteger() << ", " << f1.at(0)->getDouble() << endl;
cout << "2nd Values: " << f1.at(1)->getInteger() << ", " << f1.at(1)->getDouble() << endl;
return 0;
}
From valgrind
==12125== 40 (24 direct, 16 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3
==12125== at 0x4C29203: operator new(unsigned long) (vg_replace_malloc.c:334)
==12125== by 0x400FD8: DLinkList<Foo*>::push_back(Foo*) (DLinkList.hpp:138)
==12125== by 0x400CF3: main (Source.cpp:28)
I am not sure how the memory is being lost here, I want to say that it is because it is making a copy of it and the original is being lost. If this is the case, I am unfamiliar with how to handle it.
Again, I appreciate any help in understanding this. I have tried to look through all related questions, but I did not see anything that covered this or at least I did not understand it. Thank you!
Given the other issues pointed out in the comments such as making an erroneous usage of explicitly calling the DLinkList destructor, you are doing this in main():
f1.push_back(new Foo());
f1.push_back(new Foo(2, 5.5));
You are creating an instant memory leak here on those two lines of code that can not be recovered. You are calling new but nowhere do you save the address returned from new so that you can call delete later on for that address.
So it is main that has to manage these dynamically allocated Foo objects. Something like this:
Foo* p1 = new Foo();
Foo *p2 = new Foo(2, 5.5);
f1.push_back(p1);
f1.push_back(p2);
//...
delete p1;
delete p2;
This should address the memory leak, but this is poor programming practice in this day and age of C++. You would more than likely either use
DLinkList<Foo>
and place Foo objects in the linked list, thus not requiring any manual memory management in main, or use a smart pointer and have a linked list of smart pointers, i.e.
DLinkList<std::unique_ptr<Foo>>
Alright, so I am just exhausted and was missing the simplest thing. After comparing to other lists I created, I realized that my destructor was not deleting the nodes correctly.
template <typename T>
DLinkList<T>::~DLinkList()
{
Node *ptr = head;
while (ptr != nullptr) // Not: ptr->nextNode
{
Node *garbage = ptr;
ptr = ptr->nextNode;
delete garbage;
}
}
But I do want to thank PaulMcKenzie, was a great help and also pointed out that main does need to handle the deletion of the new calls. I will up vote his and mark it.
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.
I want to deep copy an array of int. I get an Assertion Error: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) when it goes through the destructor. Which I've been told is because It's trying to delete something that is not there. Please let me know if I am on the right track and just need to change something small, or if I am completely lost and don't know it. I can add more code if needed.
Thanks for the answers.
.h
private:
int* _myArray;
int _size;
int _capacity;
.cpp
MyVector::MyVector()
{
_myArray = new int[2];
_size = 0;
_capacity = 2;
}
MyVector::MyVector(int aSize)
{
_myArray = new int[aSize];
_size = 0;
_capacity = aSize;
}
MyVector::~MyVector()
{
if(_myArray != NULL)
{
delete[] _myArray;
_myArray = NULL;
}
}
MyVector::MyVector(const MyVector& mVector)
{
_capacity = mVector._capacity;
_size = mVector._size;
// if(mVector._myArray)
// {
// _myArray = new int[_capacity];
// copy(mVector._myArray, mVector._myArray+_capacity, _myArray);
// }
}
MyVector& MyVector::operator=(MyVector& setterVect)
{
delete [] _myArray;
if(setterVect._myArray)
{
_myArray = new int[_capacity];
copy(setterVect._myArray, setterVect._myArray+_capacity, _myArray);
}
return *this;
}
You need to make sure you are following the "Rule of Three".
Apart from copy constructor & destructor You should also provide a copy assignment operator which should do a deep copy of dynamically allocated pointer member.
On a side note, the best solution is to simply drop the dynamically allocated member and use a std::vector it saves you all the hassles of manual memory management.