Why does the actual node have to be a pointer? - c++

So when we actually create the node object, why does it have to be a pointer. Why cant be just make it a regular Node object, use . for the data and then use the arrow operator for next node.
class Node {
int data;
Node * next;
};
int main() {
Node * node1, node2; // why make it a pointer
Node node3, node4; // Why dont people leave it has non pointer,
because you already have Node* next in the class.
}

Pointers play well with dynamic allocation. You can continue using the object through pointers until you purposefully free it. Automatic objects on the other hand, get destroyed at the end of the scope leaving all pointers (and references!1) to them dangling.
If you know that you won't use any of the pointers outside the scope that contains the object itself (this is likely true for your example in main()), then go right ahead and use an automatic object.
But one final complication is that if one of the pointers is a "smart" pointer that knows how to free the object it points to, you have to create the attached object using the matching allocation function. Attempting to free an automatic (scoped)2 object will result only in misery.
1 The oft-repeated statements like "a reference is equivalent to the object itself" and "a well-defined program cannot create an invalid reference" are horribly wrong but that's too long a discussion to have here.
2 Misery also accompanies trying to free an object which is static or a member subobject or dynamically allocated using a different allocator.

You can do this for some educational purpose.
class Node {
public:
int data;
Node * next;
Node(int d, Node *nextNode = NULL) :data(d), next(nextNode) {}
Node() {}
};
int main() {
Node node3, node4(20);
node3.data = 10;
node3.next = &node4;
std::cout << node3.data << " " << node3.next->data << std::endl;
}
But in real world, in creation of linked linked, you don't know when you have to create a list. In your case its a small class, but consider if it a big class with several complex data structure. If you go in this way, unnecessarily you will create a object on stack.
It will also create ambiguity while deleting memory, you will have to take a special care. In fact, you will not be able to remove memory for your first node until execution goes out of memory.
now here is one big issue, If you are passing this list to some other function(may be creating a list in a function and returning it to caller), this first Node will go out of scope and the memory allocated to your list will be leaked.
Hope I cleared your doubt.

Try to change it into a Node object and compile the code. There should be a compilation error saying that it is an incomplete type. This is because the next field is creating an infinite loop and the compiler cannot calculate how big that field is supposed to be.

A pointer is a reference to a place in memory, since each node should reference the other node and not store its value directly, because if it would store a value you need to update it each time the other node is updated.
One can also use a pointer to allocate memory in the "heap" with the "new" keyword(dynamic storage), otherwise it could be stored in the "stack"(automatic storage), which has a very limited memory(you can get a stack overflow).

Related

Will using "delete" here actually delete the object?

I was implementing a LinkedList using C++, and I seem to have forgotten a few things when dealing with dynamically allocated memory.
I have a node class:
class Node {
public:
Node(int d) {
data = d;
next = NULL;
}
Node(int d, Node* n) {
data = d;
next = n;
}
int data;
Node* next;
};
and in my LinkedList class, I have the following method:
void remove(int n) {
Node* current;
current = head;
Node* previous = NULL;
while ( current->data != n && current->next != NULL) {
previous = current;
current = current->next;
}
if (current->data == n) {
previous->next = current->next;
current->next = NULL;
delete current;
}
else {
std::cout << "Node not found" << std::endl;
}
}
I seem to have forgotten..When I do delete current does that delete the Node ? Like the actual object that the pointer current points to? Or does it just delete the pointer? Or does the deletion of a pointer pointing to dynamically allocated memory using delete delete both the pointer and the object? Or do I need to have defined a Node class destructor for that?
It just deletes the struct -in your case node- it points to, you can still use that pointer -make it point to another node-, in fact there's no way delete the pointer itself since it's allocated on the stack. it's automatically "deleted" when you leave the function.
p.s: no need to set current->next to null
Delete just free's the memory pointed to. This has the following implications:
You are not allowed to access the memory at this location (use after free)
The amount of memory you needed for your Node object is free, meaning your program would use less RAM.
The pointer itself points either to a non-valid location or NULL, if you follow best practise and set it to NULL manually.
The data at the memory location where your object was can be overwritten by any other task that has a valid pointer on this location. So technically the Node data still remains in memory as long as nobody else overwrites it.
delete p causes the object pointed to by p to cease to exist. This means that
1, If the object has a destructor, it is called; and
2. p becomes an invalid pointer, so that any attempt to dereference it is undefined behaviour.
Generally, the memory occupied by said object becomes available to the program again, though this is really an implementation detail.
The phrase "delete the pointer" is normally a sloppy shorthand for "delete the object pointed-to by the pointer".
Assuming that you have allocated your object using new delete on a pointer does the following:
calls the destructor of the object
request that the memory is free ( when that happens is actually implementation dependent )
At some point the memory manager will free and mark it as non-accessible by the process.
Thus it is up to you to set the pointer after calling delete to an agreed value. The best practice it to set it as nullptr for the latest compilers.
It does delete the actual structure pointed to by current. Pointers remain intact. No need for defining destructor.
The delete operator is to be applied to pointer to object. The pointer is an address of memory on heap allocated by calling new. Internally there is just table of addresses allocated by new. So the key to free such memory is just that address. In your case such address is stored in variable of type pointer to Node named current.
There are few problems in your code. The problematic one is that you have no posibility to tell whether node stored in current is actually allocated on heap. It might happen that current node is allocated on stack. E.g.
void someFunction(LinkedList &list) {
Node myLocalNode(10);
list.add(&myLocalNode);
list.remove(10); //<-- disaster happens here
}
The same applies to statically allocated global variables.
You must take care of extreme cases. Think about what happens when deleted object is the first one, pointed by variable head. By deleteing its memory you end up with dangling pointer in head, pointing to either unallocated memory or memory used by someone else.
My third objection is to writing such structure at all. I hope it is just some school excercise, because in any other cases you should (almost must) use some existing list like std::list from C++ STL.
Whenever you call delete on a pointer variable, the object to which it is pointing to gets deleted from the memory, however the 4 bytes allocated to the actual pointer variable (in your case, the current variable), the 4 bytes will be freed only when the variable will go out of scope, ie At the end of the function

Do I have a memory leak in my code?

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.

Difference between setting a node equal to NULL vs. deleting a Node

Lets say I have a node struct defined as below :
struct Node
{
int data;
Node* left;
Node* right;
}
lets say i have a node Node abc and xyz and :
abc->data = 1;
abc->right=NULL;
abc->left=xyz;
xyz->data =2;
xyz->right=NULL;
xyz->left=NULL;
Later if i want to delete the node xyz, is it the same if i say:
delete xyz
vs. saying:
xyz=NULL;
Could someone explain the difference or point me in the right direction ?
No, it is not the same. delete X; statement actually calls a destructor of the object pointed by X and releases/frees the memory previously allocated for that object by operator new.
The X = NULL; statement simply assigns addres 0x0 to the pointer X and neither destroys the object pointed by X nor releases the memory as opposed to delete.
delete frees the memory, but does not clear the pointer.
setting the xyz to NULL just clear the pointer, but does not free the memory.
This is one of the many differences between C++ and Java/C#/JavaScript in its memory management -- in systems with Garbage collection the clearing of a reference/pointer such as xyz above will allow the garbage collector to later free the memory. C++ (or C) does not have garbage collection which is why memory must be managed as part of the program or otherwise you will end up with memory leaks.
As Vlad Lazarenko wrote above, these operations are not the same. In real code you should use smart pointers and do not call delete operator directly.
boost::shared_ptr<std::string> x = boost::make_shared<std::string>("hello, world!");
x->size(); // you can call methods of std::string through smart pointer
x.get(); // and you always can get raw pointer to std::string
Modern compilers allows you to write less code:
auto x = std::make_shared<std::string>("hello, world!");

Deleting objects in C++, and the new keyword

A few questions:
I was looking at the following code for a linked list on www.cprogramming.com:
struct node {
int x;
node *next;
};
int main()
{
node *root; // This will be the unchanging first node
root = new node; // Now root points to a node struct
root->next = 0; // The node root points to has its next pointer
// set equal to a null pointer
root->x = 5; // By using the -> operator, you can modify the node
// a pointer (root in this case) points to.
}
Would this code cause a [small] memory leak because he never deletes root at the end?
Also, would this be any different if 'node' was a class instead of a struct?
Finally, for this code:
#include <iostream>
using namespace std;
class A
{
public:
A(){}
void sing()
{ cout << "TEST\n";}
};
int main()
{
A *a = new A();
a->sing();
return 0;
}
Would I have to delete A before exiting main?
In what instances would I use A *a = new A() versus using A a = A() ?
1.1 Yes, although on any modern operating system when the process ends all its memory is reclaimed by the operating system. Memory leaks are a big problem for long lived processes, where memory continues to be leaked and the process continues to ask for more memory for no apparent reason.
1.2 I suppose you meant a class, not an object (an object is an instantiation of a class or of a struct)... still, there would be no difference, class and struct differ only in their default access specifier (public for structs, private for classes).
2.1 Yes (with the same caveat as in 1.1).
2.2 Usually when (a) A is too big to be placed on the stack, (b) when the object lifetime imposed by local variables (=automatic destruction at the end of the scope) is not appropriate, (c) when the number of objects to be create is not known at compile-time.
Examples:
a. A contains in its definition a really big matrix, that would take away a lot of stack space; or, A is not that big, but the current call is recursive, so putting it on the stack would be likely to lead to a stack overflow.
b. A is an object to be returned from this function (and a copy is not acceptable); or, A is to be created in this function and to be deleted in the future by some other function, but not at the end of the current scope.
c. A is a node of a linked list to be populated with data provided by the user; you create and append the nodes in a loop until the user provided data ends.
For the first part:
It might be sloppy (and tools like Valgrind will warn about it), but all memory is freed by the OS when main returns. A memory leak is more of a concern if it persists as the program continues to run.
There is no distinction in C++ between "classes" and "structs". A class simply has its initial access modified as private rather than public.
And for the later part:
Same as 1.
This is a fairly complicated question. Broadly, you'll want to use heap memory allocation (which is what new does) in cases where the object needs to outlive the current scope (e.g. to be returned by the function in which it is constructed) or its size is determined dynamically or can be very large, among other reasons.
Would this code cause a [small] memory leak because he never deletes root at the end?
Yes, however the program is terminated and the memory should be reclaimed by the OS. So any memory leak checks would flag this.
Also, would this be any different if 'node' was an object instead of a struct?
No. Structs and Classes are nearly identical, except that the default protection for a struct is public
Would I have to delete A before exiting main?
Yes. To avoid a memory leak.
In what instances would I use A *a = new A() versus using A a = A() ?
Using operator new will allocate the memory on the heap. It's preferred to allocated on the stack, unless you need your object to live past the life of the stack-frame, in which case you can either return by copy, or allocate it on the heap, where it will remain until it is deleted.
First Part
1) Yes, there is a memory leak.
2) There is no functional difference between a class and a struct.
Second Part
1) Yes, you should delete any object that you allocate on the heap.
2) In any case where you can avoid pointers (and allocating heap memory, for that matter), you should. It takes less time and uses less resources to use the stack.
In this case the lifetime of the object is so short that it makes no sense to use the heap.

Test, if object was deleted

Look to the following code, please:
class Node
{
private:
double x, y;
public:
Node (double xx, double yy): x(xx), y(yy){}
};
int main()
{
Node *n1 = new Node(1,1);
Node *n2 = n1;
delete n2;
n2 = NULL;
if (n1 != NULL) //Bad test
{
delete n1; //throw an exception
}
}
There are two pointers n1, n2 pointed to the same object. I would like to detect whether n2 was deleted using n1 pointer test. But this test results in exception.
Is there any way how to determine whether the object was deleted (or was not deleted) using n1 pointer?
As far as I know the typical way to deal with this situation is to use reference-counted pointers, the way (for example) COM does. In Boost, there's the shared_ptr template class that could help (http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/shared_ptr.htm).
No. Nothing in your code has a way of reaching the n1 pointer and changing it when the pointed-to object's is destroyed.
For that to work, the Node would have to (for instance) maintain a list of all pointers to it, and you would have to manually register (i.e. call a method) every time you copy the pointer value. It would be quite painful to work with.
When you have an object it will be at some place in memory. This is the value for both n1 and n2. When you delete the object, by releasing the memory that object used, the memory is invalid. So you can never access anything n1 points to, if it was deleted.
I suggest creating a wrapper object, which contains a counter and a pointer to the object. When you want to point to the actual object, instead you have to point to the wrapper, and when you want to delete the object, you actually call a method on the wrapper:
If you want to point to the object, you should increase the counter of the wrapper, and point to the wrapper. If you want to delete the object, you should decrease the counter and set the pointer to the wrapper to null. If the counter of the wrapper reaches zero, you can safely delete the actual object and then the wrapper.