I have this small piece of code in my IntList implementation to push_back nodes. My question is if the *pnode cause memory leak or do I need to delete it at the end.
void IntList::push_back(int data){
if (first){
IntNode *pNode = first;
while(pNode->next!=0){pNode = pNode->next;}
pNode->next = new IntNode(data);
} else
first = new IntNode(data);
}
No you don't need to call delete on pNode. You only call delete on things created with new. With the code as it is now pNode is a stack object and will automatically be destroyed when it goes out of scope at the end of the function.
You don't need delete pNode. Moreover, you can't do it in this particular case.
After you create something with new you must delete it exactly one time - once you'll never use it.
After removing the object with delete, attempt to read its contents is an undefined behavior. The pointers are generally one of the most bug generating part of the c++, so it is good that you are trying to understand it better.
You can visualize yourself this way: You can buy a house (house is a piece of memory) with new. It returns you address if it. It is your house now and can do with it what you want. You can also sell it with delete. Until this is done, you can give your friend your home address so that they can come to you. Distribution of the address, causing copying it (e.g. IntNode *pNode = first;). However, you still have only one house. So no matter how many times you copy your home address, you can sell the house only once.
I would advise using smart pointers (e.g. std::unique_ptr), but I think this program is for learning programing, so don't do it ;)
You have to delete the IntNodes created with new eventually, likely in the destructor of the container and the pop_back function. pNode itself (the pointer) was allocated on the stack, and not with new, so does not need to be deleted.
You need delete nodes on each function that removes nodes from the list, not when inserting. Not doing so would cause a leak.
If there are still allocated nodes when you destruct the object you need to iterate the whole list to remove all the nodes too. Not doing so would cause a leak too.
I suppose that this is a college assignment, as there are millions of battle-tested linked list implementations out there.
You'd do better if you maintain a tail node up to date on all functions, so you could avoid iterating the whole list to insert a node on the tail.
The code you show is not sufficient to tell if you're leaking memory or not. You show the routine responsible for allocation, but not the code where you're performing deallocation.
If you don't have any code performing deallocation, then yes, obviously that leaks. C++ does not perform automatic garbage collection as you may be used to in some other languages.
You are using naked new, so even if you do have some other code attempting to do deallocation, there's a good change it's being done incorrectly.
In C++ you generally shouldn't be using the new operator directly, and you should learn to use RAII to handle resources instead. IntList presumably uses owning raw pointers, which is another thing to be avoided. In this case you should probably be using unique_ptr<IntNode>. For example:
struct IntList {
struct IntNode {
unique_ptr<IntNode> next;
int data;
IntNode(int data) : data(data) {}
};
unique_ptr<IntNode> first;
// returns a reference to the null pointer which terminates the linked list
unique_ptr<IntNode> &get_tail() {
if (!first) {
return first;
}
IntNode *pNode = first.get(); // pNode is a non-owning pointer
while (pNode->next) {
pNode = pNode->next.get();
}
return pNode->next;
}
void push_back(int data) {
get_tail() = make_unique<IntNode>(data);
}
};
There actually is a problem with the above code, but the issue is unrelated to memory leaks. When the list is destroyed, first is automatically destroyed, which automatically destroys first->next, and so on. It's possible to insert so many elements into the list that this chain of destruction 'smashes' the function stack, leading to undefined behavior.
The problem can be fixed with an IntList destructor that destroys the nodes in the opposite order:
IntList::~IntList() {
while (first) {
unique_ptr<IntNode> tmp = std::move(first);
first = std::move(tmp->next);
}
}
It's interesting that this is an example of an exception to the Rule of Three.
Related
I have a class that contains a structure called Node and memory for this is dynamically allocated. Using the add function I am creating more Node and connectin them through the next array pointers. I am only saving my head pointer, which points to my first node. I am trying to write a destructor like below. Is it ok?
struct Node{
bool arr[30];
bool end[30];
Node* next[30];
};
class ClassName{
Node *head;
Node* newNode(){
Node * cur = (Node*)malloc(sizeof(Node));
return cur;
}
public:
ClassName(){
head = newNode();
}
~ClassName(){
free(head);
}
void add(string s,int pos,Node *cur){// 1 base index
// adding new node and next array pointers will connect them
// So after adding some nodes it will form like a tree
}
};
~ClassName(){
free(head);
}
This frees the head node. It doesn't also free any of the nodes referred to by head->next[0..29]. So no, it's not OK if you actually allocated those nodes - you will have a memory leak.
Next problem, your next array is uninitialized, so unless it's always all populated (which is obviously impossible as your tree would have no leaves), there's no way to figure out which entries are real pointers and which are garbage values. So it's impossible to fix this leak with the code as shown.
We could fix the existing malloc code to properly initialize your objects, but it brings us on to the next oddity, which is using malloc and free for objects in C++ at all.
Using new and delete would be a modest improvement (at least Node could have a constructor and destructor to properly initialize and destroy itself), but switching to owning smart pointers instead of raw pointers would be best: they initialize and destroy themselves automatically with no extra work on your part.
struct Node{
// value-initialize all those bools to false
bool arr[30] {};
bool end[30] {};
// this will initialize all entries to nullptr, and
// also takes care of deleting them on destruction
std::array<std::unique_ptr<Node>, 30> next;
};
std::unique_ptr<Node> ClassName::newNode() {
return std::make_unique<Node>();
}
The best way is to use smart pointers. But if you would like to stick to built-in pointers, it is also very easy to achieve the goal. You only need to add a simple one-liner destructor for every class, and make sure every destructor frees memory at its own level. Then the class relationship guarantees that the memory are freed in a recursive postorder manner. The beauty of this approach is that you don't have to write a recursive postorder traversal yourself. The destructors recurse themselves.
Add the following destructor for Node class:
~Node() {
for (Node *p : next) {
delete p;
}
}
Use the following destructor for ClassName class:
~ClassName(){
delete head;
}
A note: To verify that the nodes on the tree are freed in a postorder manner, you may add a print statement after each delete statement.
In a linked list that uses
struct Node {
T value;
Node* next;
}
For every used new operator (new Node()), there must be a delete operator.
An example of a destructor for such a list
~LinkedList(){
Node* tmp = head;
while(tmp! = nullptr){
delete tmp;
tmp = tmp->next;
}
}
My question is, what exactly gets "deleted" that allows me to use next pointer
even after delete is used? Does it only delete the value? How does that actually look in the memory?
In C++ when you delete an object on the heap nothing actually gets cleaned up, it just marks the memory as "free". This means that another call to new or malloc may overwrite that memory.
Accessing a deleted pointer is undefined behaviour because their are no guarantees on the data that resides there. I'm not very well versed in how the OS handles memory but I believe it could even be the case that your program no longer owns that page if that was the last item you deleted from that section of memory. If this happened to be the case then dereferencing that pointer will cause a segmentation fault on most desktop OS's.
If you wanted to safely move the head you should assign a temporary value to the next item while the pointer is alive, then you can delete the underlying object from memory.
When a data is deleted the pointer becomes undefined and for sure does not reach to memory it was pointing before, therefore there is no way to call tmp=tmp->next' after deletion.
The proper destructor declaration would be:
~LinkedList()
{
while (head != nullptr)
{
Node * tmp = head->next;
delete head;
head = tmp;
}
}
BTW.: Please read some good books on how to implement lists.
BTW.2: Use some standard containers like vector or list if you really need it.
I'm new to C++ and I found out that I have been spoiled by Java and newer programing languages like Swift. So I understand that sometimes you have to delete objects manually in C++ such as pointers. You can use the delete keyword or you can use the smart pointers. But I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.
I'm writing code that acts as a integer linked list. So I have a pointer pointing to the head and the tail of the list. When ever someone 'polls' something it should delete it from the list and then reset the head (or tail) accordingly. So I have some code that works fine for what I need it to do:
int IntegerLinkedList::pollFirst(){
if (tail == nullptr && head == nullptr) {
return 0;
} else if (head == tail) {
int ret = head->getData();
head = nullptr;
tail = nullptr;
//delete head;
//delete tail;
return ret;
} else {
IntegerNode* newHead = head->getNext();
head->setNext(nullptr);
newHead->setPrevious(nullptr);
int ret = head->getData();
//delete head;
head = newHead;
return ret;
}
}
But I never really delete the object that it was pointing at, I just remove all the pointers to it. Does that delete the object like it would in Java? Or do I have to manually delete it and how would I do that? Am I memory leaking??? Thanks so much
Also the code that updates the head is
void IntegerLinkedList::addFirst(int x){
IntegerNode* n = new IntegerNode(x);
if (head == nullptr && tail == nullptr) {
head = n;
tail = n;
} else {
head->setPrevious(n);
n->setNext(head);
head = n;
}
}
And the head was defined in the header as
IntegerNode* head;
Java has a garbage collector that essentially does what smart pointers do. That is, when the last reference to an object falls out of scope clean up the memory.
The delete keyword frees up the memory at a location the pointer points to. It doesn't actually do anything to the pointer variable itself (which is just an address).
The way to correct your code would be:
else if (head == tail) { // suppose head = 0xAD4C0080
int ret = head->getData();
delete tail; // cleans memory at 0xAD4C0080, head and tail are still 0xAD4C0080
head = nullptr; // now head = 0
tail = nullptr; // now tail = 0
return ret;
} else {
IntegerNode* newHead = head->getNext();
head->setNext(nullptr);
newHead->setPrevious(nullptr);
int ret = head->getData(); // obtain data while head still exists
delete head; // get rid of head
head = newHead; // remove stray reference to deleted memory
return ret;
}
If you attempted to use the value 0xAD4C0080 after calling delete in these examples you would get a segmentation fault.
As for smart pointers (quoting from your comment):
yes the smart pointers, but do they delete what it is pointing at or just themselves
Smart pointers delete what they are pointing to when they themselves get deconstructed (usually by falling out of scope). i.e.
void func() {
std::unique_ptr<int> pInt(new int);
} // pInt falls out of scope, std::unique_ptr<int>::~std::unique_ptr<int>() called
I'm confused on whether that deletes the pointer itself, so the
pointer can't be pointed again or if it deletes where the pointer is
pointing.
It deletes what the pointer is pointing to. The pointer must be pointing to an object that was allocated with dynamic scope (the new keyword).
I just remove all the pointers to it. Does that delete the object like
it would in Java?
Of course not.
Or do I have to manually delete it and how would I do that? Am I
memory leaking???
You have to manually delete it, using the delete keyword, and, yes, you are leaking memory unless you do that.
It is often said that it's easier to learn C++ from scratch, than to try to learn C++ if you already know Java. C++ objects work fundamentally differently than they work in Java.
And not only differently, but in ways that have no equivalent in Java, at all. There is no Java equivalent, for example, of an object instantiated in automatic scope, in C++.
The full explanation of various scopes of C++ class instances cannot be fully given in a brief answer on stackoverflow.com. You need to get a good book on C++, and start reading it.
And forget everything you know about classes from Java. C++ classes don't work that way. The longer you keep trying to draw analogies with Java, the longer it will take you to learn how to use C++ classes correctly.
Yes, some of the pain can be helped by using smart pointers, which will take care of some of the pain points. But understanding smart pointers in of themselves also requires complete understanding of C++'s class model. Smart pointers do not solve everything, and it is important to understand how C++ classes work, in order to understand what problems smart pointers do solve, and what problems they do not solve.
It depends on what the type is for head and tail. In C++, there are operators (e.g., operator=), and there are destructors. This can lead to certain interesting consequences. Take this example:
#include <memory>
int main() {
// allocate memory
int* ptr = new int;
// store in smart pointer
std::unique_ptr<int> smart_ptr(ptr);
// create another wrapped pointer
std::unique_ptr<int> smart_ptr2(new int);
// throw away location of allocated memory
ptr = nullptr;
// free memory by assigning to smart pointer
smart_ptr = nullptr;
// we can call delete safely here because ptr is null
delete ptr;
// data pointed to by smart_ptr2 will
// be deleted at end of scope
return 0;
}
Additionally, there are two operators for allocating memory, operator new and operator new[], which must be free'd using delete and delete[] respectively.
A more detailed explanation of these concepts may be beyond the scope of this site.
Am I memory leaking???
Yes, if you new something, you must delete somewhere. Assigning pointer to nullptr won't ever affect the allocated data.
But I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.
The delete keyword will delete the content at the address you send to it. It won't delete named variable, as variable on the stack are destructed at the end of the scope. Deleteting manually something with automatic storage led to undefined behaviour.
I see you are confused about std::unique_ptr No, they are not deleting themselves. Like any other variable, thier destructor are called and the variable is destructed. The thing about std::unique_ptr is that in their destructor, they delete the data they point to, with you having to delete it yourself. You should read about the RAII idom.
There's a thing about your code, these lines in particular:
head = nullptr;
tail = nullptr;
delete head;
delete tail;
This won't do a thing. You are deleting no data, as head and tail point to nothing. Since the delete keyword deletes the data pointer are pointing to, it won't delete anything.
However, take this example with std::unique_ptr:
{
std::unique_ptr<int> myPtr;
myPtr = std::make_unique<int>(); // or you can use `new int;`
myPtr = nullptr; // The old int you allocated with `std::make_unique` is deleted.
myPtr = std::make_unique<int>(); // assign a newly allocated int
}
// Here, myPtr will free his data as it leaves the scope.
If you use the new keyword, then you always need to use delete. Memory allocated using new is not managed.
Currently your program is leaking memory in the pollFirst method, because you do not free the memory that head and tail point to before re-assigning them. You can do this by calling delete head and delete tail before re-assignment.
You should look into using one of the smart pointer types, such as unique_ptr, if you want automatic management of the memory your pointers point to.
There are few things you should know about C++.
Destructor (DTOR) : Destructor is something which you define for your class. If you don't define a destructor of your own compiler does it for you.
When you call delete for a pointer the DTOR of that class is called which does the necessary cleanup. In order to test it, please put a breakpoint to the DTOR and run the code. Once the control hits DTOR, check the call stack, you will find out that last frame below the DTOR in call stack is the line where you call delete.
As far as the smart pointers are concerned, it does something similar to the garabage collector. Smart pointers have something called reference count. The moment reference count of a smart pointer goes to 0, the DTOR is called.
NOTE: It is advised to write your own DTOR if you have a data member in the class which is pointer.
I was just curious as to if this code would create multiple memory leaks, or if it would get cleaned up correctly.
Node *newNode;
for (int i = 0; i < 10; i++)
{
newNode = new Node();
}
delete newNode;
So obviously the code doesn't do anything, but it does help me explain my scenario. Am I allocating memory 10 times and when I'm deleting the pointer leaving 9 orphans? Or am I reusing the same space being allocated and removing the orphan correctly?
Thanks in advance!
Yeah this is leaking memory. When you do:
newNode = new Node();
You are redefining the pointer to point to newly-allocated memory, in effect losing hold of a way by which to address the previously-pointed to memory in order to delete it.
So when you leave the loop, the newNode pointer points to the last-allocated (tenth) memory/Node. When you delete newNode you are deleting only that memory. You no longer have a way by which to delete the others.
As Zhi Wang pointed out, you can use some form of smart pointer (unique_ptr or shared_ptr in C++11 for example). These smart pointers are basically wrappers around regular pointers which have additional semantics which prevent this kind of leak. If you used one of these, the memory/objects would automatically be deallocated when they went out of scope (upon ending of the current iteration of the for loop in that case).
However, I don't think this would solve your situation in this case. I doubt you want to delete the 10 objects as soon as you create them. Rather, you probably want to store these objects in a container like a std::vector or at the very least have an array of pointers pointing to each of these allocated instances. That way you will have the objects around (which I believe is what you want, since you're constructing them at all) and also have a way by which to remove them later.
Yes, your code leaks memory. Your first guess at the behavior is correct. This code
Node *newNode;
for (int i = 0; i < 10; i++)
{
newNode = new Node(); // allocate memory 10 times in a loop...
}
delete newNode; // ... but free the memory only once!
allocates memory 10 times (the new operator inside of the for loop), but frees the memory used by only one of those objects (the delete operator at the bottom). Naturally, this leaves the other 9 objects orphaned—the memory they consume is still allocated, but you now have no way of accessing it to free it. That is, of course, the very definition of a memory leak.
By contrast, this code
Node *newNode;
for (int i = 0; i < 10; i++)
{
newNode = new Node(); // allocate memory 10 times in a loop
delete newNode; // ... and free the memory each time
}
does not leak any memory, because there is one call to delete for each call to new. That's the big rule you have to keep in mind: if you don't match up each call to new with a corresponding call to delete, you will have a memory leak.
Or, perhaps the even better rule when you're working in C++ is never to use raw pointers in the first place. The C++ standard library provides a couple of great wrapper classes that implement the RAII idiom for pointers, which ensures that the objects pointed to get properly destroyed and therefore the memory that they consume gets freed. Start your research either in your favorite C++ book, or on Wikipedia.
Suppose I have a doubly-linked list defined by the class
class list
{
/*...*/
private:
struct node
{
node* prev;
node* next;
int* value;
}
node* first; //NULL if none
node* last; //NULL if none
/*...*/
}
If I wanted to make a destructor for this list do I have to explicitly delete the value?
list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move;
move = first;
}
}
Would the above work to ensure that no memory is leaked? Or do I have to do:
list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move->value;
delete move->prev;
delete move;
move = first;
}
}
I'm confused as to how I can make sure that no memory is leaked in this case. How do I deal with the pointers in the nodes specifically? If I delete move does it automatically take care of these?
You need to pair each new with exactly one delete. That is, you probably don't want to delete prev (this node already was deleted) but you want to delete value. Well, I'd embed the value into the object and not point to it:
struct node
{
node* prev;
node* next;
int value;
};
If the value absolutely needs to be a pointer, I'd use a std::unique_ptr<int> (or, if you need to use C++ 2003, a std::auto_ptr<int>).
For each successful new expression, call delete exactly once on that object.
For each successful new[] expression, call delete[] exactly once on that object.
That means that neither of your cleanup functions are OK:
The first function forgets to delete the value, which means a memory leak.
The second function, by deleting both move and move->prev at each node in the list, risks deleting most nodes twice, which is Undefined Behavior.
To avoid the memory leak for the first function, simply store the integer directly instead of allocating it dynamically.
Whether you have to delete the memory pointer by the value member - only you can know. It is a question of memory ownership, a question of your design. If the list owns the data memory pointed by the value members, then you have to delete it in the list destructor (i.e. when the list dies, the data it owned dies with it).
If the list does not own the value memory, then you are not supposed to delete it. Again, only you can answer the question of whether your list is supposed to own the value memory. It is a matter of your intent.
Now, as for the memory occupied by node objects, it is obviously owned by the list, so it has to be carefully deallocated in the destructor. The first version of your destcructor is close to being correct (the second makes no sense at all), except that it written in a slightly obfuscated fashion. This should be sufficient
list::~list()
{
while (first)
{
node *move = first;
first = first->next;
delete move;
}
}
(Again, if you have to delete value, then delete move->value should be added to your cycle before delete move.)
P.S. Once you get this, you might want to look into various smart pointer classes, which allow you to explicitly express memory ownership relationsips, thus making them known to the compiler. When used properly, they will make memory management almost automatic.