I was trying to build a linked list without allocating memory dynamically. Note that I can build linked list using new operator.
The below code does not work. When I debugged it I found out (as much as I can understand) that Node a(n, head) is allocated at the same address in the memory every time so the a stores pointer to itself. If someone can explain to me, it would be of great help.
class Node {
public:
int val;
Node *next;
Node(int n, Node *ptr = NULL) {
val = n;
next = ptr;
}
};
class LinkList {
Node *head = NULL;
public:
void insertNode(int n) {
Node a(n, head);
head = &a;
}
void print() {
Node* ptr = head;
while (ptr != NULL) {
cout << ptr->val << endl;
ptr = ptr -> next;
}
}
};
int main() {
LinkList a;
a.insertNode(3);
a.insertNode(4);
a.print();
return 0;
}
No, the same memory is not allocated to all objects of a class... but the same memory is allocated for the local variables of every function. Once a function returns, all its local variables are destroyed, so its local variable memory is now unused, and the next function call will use it for its local variables. Hence every time you call insertNode it uses the same memory to hold a. And when you call print, it uses that same memory to hold ptr.
This is just what usually happens. Not all compilers do it the same way, so you can't rely on it. And if you had extra function calls between main and insertNode then insertNode's variables wouldn't get the same addresses as they do when main calls insertNode directly.
Also note that because you aren't allowed to use pointers to variables that were already destroyed, the optimizer is allowed to guess that when you use a pointer, it points to a variable that hasn't been destroyed, and sometimes this causes really weird behaviour. So you mustn't use pointers to destroyed variables, ever, even if you would be okay with getting the wrong data. The technical term is undefined behaviour.
Related
Im having difficulty describing this problem succinctly so be kind.
I have a Tree object that has an attribute root which is a pointer to a node object. When I initialize the Tree object the root is unknown so i assign it to a nullptr.
In a function after some computation I find the root node of a complete binary tree. I now want to hand this value over to my Tree.root pointer. However since this function is removed from the stack after execution and Tree.root pointer appears empty when I run it later.
class Tree{
public:
Node *root;
Tree(){
root = nullptr;
}
};
void worker(Tree *t){
// Perform some computation
// Since the var rootFound only exists in this function.
// After executing doesn't the memory address reallocated
// and therefore the root points to an unknown memory address?
t-> root = &rootFound;
}
int main(){
Tree t{};
Tree *ptr = &t;
worker(t);
// t pointer is null
return 0;
}
I was thinking I could assign the root pointer found by the function to the heap (use new ) and then assign my Tree pointer to it but Im not sure how to go about deleting this value. Also since any node has left and right Node pointer Im not sure if the pointers lose the memory address they are pointing too or if they too will be added to the heap.
I could also just be overthinking this.
Since you posted an incomplete code in your question, I will be forced to assume things.
I will assume your implementation look like this:
void worker(Tree *t){
Node rootFound;
// do stuff where eventually rootFound = something
t->root = &rootFound;
}
In this case, yes, t->root will point to a dead object once worker is finished.
I was thinking I could assign the root pointer found by the function to the heap (use new ) and then assign my Tree pointer to it but Im not sure how to go about deleting this value.
There is two kind of raw pointer in C++: owning pointer and non owning pointer.
If t->root is a owning pointer, it means you will call delete on it.
If t->root is not a owning pointer, it means you will not call delete on it.
Then if it is owning, you can totally do new Node{...} an assign to it.
If on the contrary it is not and you want to create an new tree in this function and delete it later, you will need to give an owning pointer back to the caller, something like this:
Node* worker(Tree* t) {
Node* rootFound = new Node{}; // create a whole new tree here
t->root = rootFound; // assign it to the tree
return rootFound; // return a owning pointer to the caller
}
Then, in your main:
int main(){
Tree t{};
Tree *ptr = &t;
Node* owning = worker(ptr);
// do stuff with t
// delete the owning pointer.
delete owning;
return 0;
}
Of course, there is a better way to separate owning and non owning pointer.
In modern C++, owning pointer are declared like this: std::unique_ptr<T> and non owning are written T* and assume you don't have to delete it.
If we change your data structure just a little bit to express what pointer is which, it would look something like this:
class Tree{
public:
// Here! Root is owning.
std::unique_ptr<Node> root;
Tree(){
root = nullptr;
}
};
// Tree is non-owning, so we write it just like before.
void worker(Tree* t){
// ...
}
The neat thing about std::unique_ptr is that is clears memory in its destructor so you don't have to worry about deleting:
int main() {
// make_unique will call new
std::unique_ptr<Node> node = std::make_unique<Node>();
// Here, unique_ptr will call delete
}
So in the end, Tree will clear up itself at the end of main:
int main(){
Tree t{};
Tree *ptr = &t;
// worker can do t->root = std::make_unique<Node>();
worker(ptr);
return 0;
// Here, t.root will call delete if not null
}
I am new to C++ and I am trying to initialize a vector of struct as code below.
struct Node{
int x;
Node *p;
int rank;
Node(int x) {
this->p = this;
this->x = x;
this->rank = 0;
}
};
int main() {
vector<Node> disjointSets;
for (int i = 0; i < 50; i++) {
Node a(i);
disjointSets.push_back(a);
}
}
In main, I try to create a Node a each time and push it into vector. But I later find there is an issue that a is always created at the exact same memory location. Therefore, the p, which is supposed to point to each Node itself will point to the last element after the loop. May someone explain why Node a is always created at same memory address and how to solve the issue?
You have undefined behavior, because you haven't defined a custom copy constructor for your Node class.
disjointSet.push_back(a); makes a copy of a. This is using the default copy constructor, which simply does an element-wise copy of all the member variables. So in the copy, p points to the address of the original Node, not itself. But that Node is destroyed when the loop iteration ends, so the pointer is no longer valid. It's implementation-dependent, but pretty common that the loop happens to use the same stack memory for a each time through the loop, so p in all the elements points to that same address, which is no longer a valid Node.
You need to define a copy constructor that sets p to the address of the copy:
Node(const Node &oldnode) {
p = this;
x = oldnode.x;
rank = oldnode.rank;
}
and a copy assignment operator:
Node& operator=(const Node &oldnode) {
if (&oldnode != this) {
x = oldnode.x;
rank = oldnode.rank;
}
return *this;
}
Your node's are created on the stack. And address which is assigned inside the constructor points to the stack. If you want the Nodes a constant address which doesn't change while they are moved/copied into the container you need to heap allocate them and use a vector of Node pointers. E.g. a vector<std::unique_ptr<Node>>.
You are not using heap memory. Storing the address of a local variable and trying to access it elsewhere is UB. If I'm correct, The answer for "why" the same memory space is taken for each iteration of the loop is implementation defined and in this case, it is reusing the same stack space.
I came across a piece of code that use new to allocate dynamic memory in a function, then calls this function in the main function. I suspect there are some memory leak issue, but I do not know exactly how to fix it. The following code is simplified to demonstrate the problem:
#include <iostream>
#include <vector>
using namespace std;
// Definition for singly-linked list.
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* createList(void);
int main(){
ListNode* my_list = createList();
//... some code
// how to delete those objects created by new?
return 0;
}
ListNode* createList(void) {
ListNode preHead(0), *p = &preHead;
vector<int> sum = {1, 2, 3, 4, 5};
for (decltype(sum.size()) i = 0; i != sum.size(); i++){
p->next = new ListNode(sum[i]);
p = p->next;
}
return preHead.next;
}
If I understand it correctly, The function createList() creates a list which has 6 ListNode objects.
Except the first object in the list (which is preHead), the other 5 objects are all dynamically
allocated using new. Finally, function createList() returns a pointer to the second object in the list,
which is a pointer to dynamic memory.
My question is:
Is my_list a normal pointer or pointer to dynamic memory? How do we decide the type of my_list.for example, if I write the following code
ListNode l1(2);ListNode* my_list = &l1;
Then my_list will be a normal pointer to ListNode object. What is the difference between the 2 situations?
The last 5 objects in the list are created using new, how to delete them in main() after using the list? Do I have to traverse the list and start deleting from the end of the list until all objects created dynamically are deleted?
If that is the case, I think it will be cumbersome and inconvenient. How to improve createList() under the condition that it still returns a pointer to ListNode object.
Agreeing with the aforementioned suggestions of using std::list, I want to add the following:
Q1) where do you see the distinction between a "normal pointer" and "pointer to dynamic memory"? A pointer to x is a pointer to x. You should know whether it is yours to delete.
Q2) You either do what you suggested (deleting from the end) or
void clearList(ListNode* p) {
ListNode* nextP;
while (p != NULL) {
nextP = p.next;
delete p;
p = nextP;
}
}
Is my_list a normal pointer or pointer to dynamic memory?
your pointer is a pointer, it is a variable that points to memory, there really is no difference between a pointer that points to memory that was dynamically allocated or memory that isn't. The only difference is you have to clean up dynamically allocated memory that you own.(Which you should know if you allocated it dynamically or not)
A safe alternative to dynamic memory is to use std::shared_ptr and std::unique_ptr I won't go into a lot of detail here but they can save you some trouble with memory management, so look them up.
How do we decide the type of my_list.for example, if I write the
following code
ListNode l1(2); ListNode* my_list = &l1;
This is a pointer to memory allocated on the stack (So not dynamic as you didnt call new)
The last 5 objects in the list are created using new, how to delete
them in main() after using the list? Do I have to traverse the list
and start deleting from the end of the list until all objects created
dynamically are deleted?
Yes, you could loop through them all and delete them that way if you would like, but how are you going to get to the previous? Another solution is to do:
ListNode* tempPtr;
while(my_list) // This works since you are initializing next to null.
{
tempPtr = my_list->next;
delete my_list;
my_list = tempPtr;
}
If that is the case, I think it will be cumbersome and inconvenient.
How to improve createList() under the condition that it still returns
a pointer to ListNode object.
There really isn't, if you don't dynamically allocate your memory here or use a static or global variable, it will be gone at the end of the function. You could however use a std::vector or an std::list to do the exact same thing you are currently doing.
I'm trying to make a List class using the concept of linked lists, and while I was originally using the C++ standard new keyword, I decided to switch it out for the C++11 std::shared_ptr. However, I can't get the program to function properly when using smart pointers, as it crashes. Here are some bits of code before the change:
class List
{
public:
void push_back(...) {
Node *temp = new Node;
...
if (!head) {
head = temp;
return;
}
else {
Node *last = head;
...
last->next = temp;
}
}
...
private:
Node *head = nullptr;
};
And here's what it looks like with the change:
class List
{
public:
void push_back(...) {
std::shared_ptr<Node> temp(new Node);
...
if (!head) {
head = temp.get();
return;
}
else {
Node *last = head;
...
last->next = temp.get();
}
}
...
private:
Node *head = nullptr; // don't need this to be a smart ptr
};
I feel like the problem might be that head and last aren't dynamically allocated and maybe they need to be to work with a shared_ptr, but I'm not sure. What exactly am I doing wrong and how can I fix it? I really hope this isn't a duplicate because I can't seem to find anything that solves my problem. Thanks.
Edit:
Here's the Node struct:
struct Node{
int data;
Node* next;
};
The reason to have std::shared_ptr in the first place is to have std::shared_ptr take complete and full ownership of the pointer, and make it std::shared_ptr's responsibility to delete it, once the last reference to the pointer goes away. That's what std::shared_ptr is all about.
This means that once a pointer is placed into a std::shared_ptr, the std::shared_ptr now takes complete and full responsibility of managing the pointer. It owns it completely.
It, therefore, makes no sense to put a pointer into a std::shared_ptr ... and then immediately take it out:
head = temp.get();
There are reasons for the get() function to exist, but this isn't one of them.
In order to use std::shared_ptr correctly, everything must be a std::shared_ptr. head needs to be a std::shared_ptr:
std::shared_ptr<Node> head; // yes, it does need to be a smart ptr
Why does it need to be a std::shared_ptr? Well, if it's not, what do you think will happen when this:
std::shared_ptr<Node> temp(new Node);
Specifically, when this temp smart pointer gets destroyed, when this function returns? Well, since it will be the last std::shared_ptr that referenced this Node, it will happily delete it. The fact that you get() it earlier, and placed it into head doesn't matter. So now you have a head that points to a deleted Node. Hilarity ensues.
And this is why everything must be a std::shared_ptr. Not only head, but also Node's next member also needs to be a std::shared_ptr, too.
Now, there is a pitfall involving circular references, that comes into play when std::shared_ptr enters the picture. But that's going to be a different question.
Your main issue is that if you're going to use shared_ptr, best to use it all the way. Make next a shared_ptr instead of a raw one.
struct Node {
int data;
std::shared_ptr<Node> next;
}
What std::shared_ptr does under the hood is keep a count of how many references there are to a pointer. When you use copy constructors or operator= it increases a reference count. When an instance falls out of scope resulting in the destructor being invoked (or you give it a different pointer with operator=) the reference count decrements. When the count is zero the pointer is destroyed.
// pass by value invokes copy constructor (refcount + 1)
void myFunc(std::shared_ptr<MyClass> var) {
// Code using var
} // end of function invokes destructor (refcount - 1)
void run() {
std::shared_ptr<MyClass> ptr(new MyClass); // refcount = 1
myFunc(ptr); // refcount = 2
// After myFunc returns refcount = 1
}
int main() {
run(); // refcount = 1
// After run returns, refcount = 0 and the pointer is deleted
}
By using get() you introduce a pointer to memory that may be deleted at some point, regardless of whether or not that pointer is around. This can lead to segfaults as the raw pointers are pointing to memory that shared_ptr deleted.
This is because get() does not affect the reference count. How could it? It's not a shared_ptr any more so that class definition has no way of knowing what you do with it, or when it gets deleted. If get() increased the reference count there would be nothing to decrease it afterwards, and the memory would never be released. That's a memory leak!
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.