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.
Related
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.
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 implement a BST in C++, and I came across these two ways of creating a node:
node* z = new node();
z->key = d;
z->left = NULL;
z->right = NULL;
and then this:
node* y = NULL;
node* x = root;
node* parent = NULL;
What is the difference in calling the new operator or not?
EDIT
so for example, whats the difference between:
node* q = new node();
and
node* q;
and why would you choose one way or the other? Is there an advantage for one way or the other?
To answer the question in the comment, yes there is a difference.
When you do node* q = new node() you declare a pointer to a node object, and then at runtime dynamically allocate memory enough for one node object, and calls the default constructor (alternatively, value initializes the object, it depends on the class/struct), and finally you assign the pointer to the newly allocated object to q.
When you do node* q; you just declare a pointer to a node object, and that's it. What the pointer will be pointing to depends on where you declare the pointer: If you declare it as a global variable, it is initialized to zero, and becomes a null pointer; If you declare it as a local variable its value is indeterminate, and will in reality seem to be random. Neither is a valid pointer, and dereferencing it will lead to undefined behavior. There is also a third alternative, and that's where you declare node* q; as a member variable in a class or struct, then the initial value depend on how the class/structure is created and initialized (for example if the structure is value initialized, if there's a constructor that initializes it, etc.).
I'm pretty sure (Someone correct me if i'm wrong), using the new operator allocates dynamic memory for that variable. The variables will most likely already have some garbage value assigned to them that gets overridden when you assign a new value to them. Whereas assigning it NULL just assigns it whatever the NULL value is (probably 0000000).
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.
I have to write a stack class template using arrays in C++ for my assignment.
Here is my code:
#include <iostream>
template <typename Type>
class Stack {
private:
int top;
Type items[];
public:
Stack() { top = -1; };
~Stack() { delete[] items; };
void push(Type);
bool isEmpty() const;
Type pop();
Type peek() const;
};
int main (int argc, char *argv[]) {
Stack<double> st;
return 0;
}
template<typename Type>
void Stack<Type>::push(Type item) {
top++;
if(top == sizeof(items) / sizeof(Type)) {
Type buff[] = new Type[top];
std::copy(items,items+top,buff);
delete[] items;
items = new Type[2*top];
std::copy(buff,buff+top,items);
delete[] buff;
}
items[top] = item;
}
template<typename Type>
bool Stack<Type>::isEmpty() const {
return top == -1 ? true : false;
}
template<typename Type>
Type Stack<Type>::pop() {
//TODO
return items[top--];
}
template<typename Type>
Type Stack<Type>::peek() const{
//TODO
return items[top-1];
}
It compiled fine using "g++ -Wall", however when I run the program, I got this error:
* glibc detected * ./lab3: munmap_chunk(): invalid pointer: 0x00007fff41a3cdf8
After trying out a bit with GDB, I found out the error arose from the line:
'free[] items' in the destructor.
I don't understand why freeing an array results in a memory leak? Any clues?
You should only delete[] what you have explicitly allocated with new[]. Your items member is not a dynamically allocated array, so you must not free it as if it were.
On the other hand, you have
Type items[];
which doesn't actually allocate any space in your object instances for the stack.
I don't think that's a memory leak! It's a crash occurring because you deleted a non-heap object.
You haven't new'd items, so you can't delete it in the destructor. Assuming you require 'Stack' to be a dynamically sized class then the items array must be dynamically allocated in which case the declaration for items should be
Type *items; (as hacker mentions above)
and the constructor should call 'items = new Type[ARRAY_SIZE]' to allocate the memory, or at the very least initially assign the 'items' pointer to NULL.
Edit based on comments -
To complete and secure the memory allocation responsibilities for this class you should also include a copy constructor and an assignment operator which allocates new memory and copies the values stored in items to the new object. This avoids the pointer simply being copied by the compiler generated copy constructor or assignment operator which would lead to multiple objects pointing to the same dynamically allocated memory. Upon destruction of the first of these objects this memory will be deleted. Further use of the now deleted memory by the other objects which share the pointer would be likely to result in a crash.
Rather than adding code here I refer you to the code in Martin's answer for this question.
items is a pointer to Type. This pointer must be initialised
before it is used (it is a wild pointer as it is). That
is why your program crashes. That it happens in the
destructor is a coincidence. It could just as well have
happened earlier. E.g. in push() memory is overwritten in the
location that items happens to point to.
You need to allocate memory for a number of elements. See below.
You already have the logic for the dynamic growth of the
array in place. But an array in C++ does not know its size
(it is just a pointer of some type). You need to keep track
of the current capacity/size. Thus instead of
sizeof(items)
define a new member to hold the current capacity.
E.g.:
int capacity;
and in the constructor:
capacity = 100;
items = new Type[capacity];
The last line allocates a number of elements and is the main solution to your problem.
And in push():
if (top == capacity / sizeof(Type)) {
The logic for reallocation will need to change. E.g.:
capacity *= 2;
items = new Type[capacity];
instead of
items = new Type[2*top];
I have just sketched out a solution here. Yon can fill in the details.
Note: you have only one instance of Stack in your program; body of main() is:
Stack<double> st;
If you instead were to assign one instance of Stack to another instance, e.g.
{
Stack<double> st;
Stack<double> st2 = st; //Copy constructor will be invoked for st2. If not defined the compiler generated copy constructor will do a copy of the pointer value.
Stack<double> st3;
st3 = st; //Assignment operator will be invoked for st3. If not defined the compiler generated assignment operator will do a copy of the pointer value.
}
then the copy constructor (to work for st2) and the
assignment operator (to work for st3) for Stack must be
defined properly (make a copy of the referenced member
items). Otherwise a double or triple delete in the destructor and
undefined behavior (e.g. a crash) will be the result when
st, st2 and st3 goes out of scope at the close brace.
The first thing I've seen is that you're likely to mean Type *items, not Type items[].
And then you don't want to (can't) use sizeof on the dynamically allocated data.