I have this test program. I don't know how to delete struct in the list using iterator.
#include<iostream>
#include<list>
using namespace std;
typedef struct Node
{
int * array;
int id;
}Node;
void main()
{
list<Node> nlist;
for(int i=0;i<3;i++)
{
Node * p = new Node;//how to delete is later?
p->array = new int[5];//new array
memset(p->array,0,5*sizeof(int));
p->id = i;
nlist.push_back(*p);//push node into list
}
//delete each struct in list
list<Node>::iterator lt = nlist.begin();
while( lt != nlist.end())
{
delete [] lt->array;
delete &(*lt);//how to delete the "Node"?
lt++;
}
}
I know how to delete the struct separately. It's like this:
Node * p = new Node;
p->array = new int[5];
delete [] p->array; //delete the array
delete p;//delete the struct
However, when it is pushed back into list, I don't know how to delete it according to the list iterator.
list<Node>::iterator lt = nlist.begin();
while( lt != nlist.end())
{
delete [] lt->array;
delete &(*lt);//how to delete the "Node"?
lt++;
}
You could use the list erase to delete a node from anywhere in between the list.
list<Node>::iterator it = nlist.begin();
advance(it,n); \\n is the node you want to delete, make sure its less than size of list
it = mylist.erase (it);
Alternatively, if you want to delete elements from either ends of the list you can use the
pop_back or the pop_front member functions.
Since you are declaring the list with list<Node> when you do:
nlist.push_back(*p)
it is actually creating a Node() and copying the data from the node you just dynamically allocated but not using the actual pointer. And then you try to delete a pointer from the object that the system will automatically delete:
delete &(*lt); // this causes double free
You need to declare the list like list<Node*> so that the pointer is inserted into the list. Although you should not really deal with this kind of allocation in c++, with a couple of modifications your code should work:
int main()
{
list<Node*> nlist;
for(int i=0;i<3;i++)
{
Node *p = new Node;//how to delete is later?
p->array = new int[5];//new array
memset(p->array,0,5*sizeof(int));
p->id = i;
nlist.push_back(p);//push node into list
}
//delete each struct in list
list<Node*>::iterator lt = nlist.begin();
while( lt != nlist.end())
{
delete [] (*lt)->array;
delete *lt;//how to delete the "Node"?
lt++;
}
return 0;
}
use list.erase
But you are really doing that non-c++ way. You do not need allocate int[5] with new. Writing int[5] does what you want. Your Node type defined in c-way. In c++ you do not need to wrap it with typedef
Related
So lately I've been learning C++, and I am studying Linkedlist now.
I am wondering why don't we create Nodes with an array, let's say:
#include <iostream>
using namespace std;
struct Node {
int data = 0; //data
Node* next = nullptr; //next node in the linked list;
};
void deallocateLinkedList(Node* n)
{
if (n == nullptr) // An empty list; nothing to delete
return;
else{
deallocateLinkedList(n->next);
delete n;
n = nullptr;
}
}
int main()
{
int k;
cout<<"enter k as number of nodes"<<endl;
cin>>k;
Node* n = new Node [k]; //creates dynamic array;
for(int i =0;i<k;i++)
{
if (i==k-1)
{
n[i].data=i;
n[i].next=nullptr;
}
else
{
n[i].data=i;
n[i].next = &n[i+1];
}
}
deallocateLinkedList(n); //pointer points to the first node;
cout<<"programmed finished"<<endl; //indicates successful running
return 0;
}
In this case, the Nodes are linked and also put into an array;
However, the deallocate programme doesn't run completely and exit without error
Is there any problem with this style of creating Linked List or just the deallocation problem?
What If I Put All Nodes of LinkedList into an Array?
Then that's where the nodes are.
However, the deallocate programme doesn't run completely and exit without error
Is there any problem with this
Yes, there is a problem.
The problem is that you may only pass a pointer to delete if you got the pointer from new (and it must be deleted at most once, and if you created an array, then you must use delete[]).
When you do delete n;, you'll find that you never assigned any of n->next (which will be the n in the recursive call) to have a pointer value that was returned from new. As a consequence, the behaviour of the program is undefined.
If you allocate objects like this:
Node* n = new Node [k];
then you must deallocate like this:
delete[] n;
I have classes A and B. Class B has a pointer to class A as a field, pointing to a list:
struct A {
A* next;
char* txt;
...};
struct B {
A* next;
int length;
...};
I make each element of this list in this way:
void B::add_elem(char* str) {
A* tmp;
tmp = new A;
tmp->txt = str;
tmp->next = next;
next = tmp;
}
And I have to delete the list at the end. Will it be deleted by default with a destructor of class A, as I've called new A(but I made my destructors to print messages, there were no ones) or should I delete it explicitly (I've tried, it was a mistake in compilation)? Help, please.
B::~B() {
int i;
A* tmp;
cout<<"del list\n";
if (next) { // at least one elem
tmp = next;
while (tmp->next) {
tmp = tmp->next;
delete next;
cout<<"del elem\n";
next = tmp;
}
delete tmp;
}
}
The lifetime of any pointer which is created with new must be managed manually by the creator using a matching delete to free the memory.
This means that every class owning a raw pointer MUST take care of its deletion. This is usually done in the destructor. If you are using C++11 you can use a unique_ptr instead of a raw pointer which will manages his own lifetime. This will help you get rid of many error and memory leaks but will add a few more constraint to your design. In most cases those constraint are what you would actually want to have.
For a nice treatment of the memory management problems in C++ you can take a look at https://isocpp.org/wiki/faq/freestore-mgmt
Oh, it works! It turned out, that I've forgotten to give memory to some field but in the destructor I wanted to delete it. It was a complicated class: some static fields and one dynamic: a dynamic massive, each member of which is a pointer to a list.
At last, this destructor works:
set::~set() {
int i;
elem* tmp;
for(i=0; i<size; i++) {
if (table[i].next) { // at least one elem
tmp = table[i].next;
while (tmp->next) {
tmp = tmp->next;
delete table[i].next;
table[i].next = tmp;
}
delete tmp;
}
}
delete[] table;
cout<<"del set\n";
}
nirvana#lpt00:~/cpp/new$ ./a.out
new set
new list
new list
new list
new list
new list
new el
new el
del el
del el
del list
del list
del list
del list
del list
del set
Thanks everyone!
I have an array of pointers to a structure called "table" (the structure is called Node).
I declare the array as so in the class:
Node * table;
Then, in another method, I initalize the table:
this->table = new Node [this->length];
And everything works fine. this->length is a valid entry, this->table is pointing to the right array, and etc. However, then I try to change the value of the elements:
for(int i = 0; i < this->length; i++) {
this->table[i] = new Node;
}
Or even
for(int i = 0; i < this->length; i++) {
this->table[i] = 0;
}
And everything starts bugging out. Why can't I set these pointers to anything?
This is the error I get:
(Where line 15 is the line of "this->table[i] = new Node;").
I hate to post long segments of code, so here's a shortened version of the code itself:
template <class T, class S>
class HashMap {
public:
HashMap();
private:
struct Node;
Node * table;
static const unsigned length = 100;
};
template <class T, class S>
HashMap<T, S>::HashMap() {
this->table = new Node [HashMap::length];
for(int i = 0; i < HashMap::length; i++) {
this->table[i] = new Node;
}
}
template <class T, class S>
struct HashMap<T, S>::Node {
T value;
S key;
Node * next;
};
No research I'm doing is telling me what the error is; any help is appreciated!
You don't have an array of pointers. You have an array of Nodes. Apparently, what you want is something like this:
Node ** table;
...
this->table = new Node*[this->length];
Or maybe you don't actually need an array of pointers, but simply an array of nodes. In that case, no extra initialization is needed beyond:
this->table = new Node[this->length];
Beyond that, unless this is a learning exercise, take a look at the standard library, which has dynamic arrays and hash maps all ready for you.
table is not an array of pointers. It's an array of Nodes (or rather, it points to an array of Nodes). The type of table is Node*; the type of table[i] is Node, not Node*.
If you actually do want an array of pointers, then you need
Node** table;
table = new Node*[length];
Or better still, something like
vector<unique_ptr<Node>> table;
table.resize(length);
You do not have declared an array of pointers.
Node *table(point to a node)
Node **table(point to an array Nodes)
Node** table;
table =new Node*[this->length];
for(int i=0;i<this->length;i++)
{
table[i]=new Node;
}
this->table = new Node [HashMap::length];
this->table is of type Node* and new Node [HashMap::length] also returns a Node* , i.e. an array of Node of lenght HashMap::length is created and the array address is stored in this->table pointer.
this->table[i] = new Node;
As an example, we can define:
int* arr = new int[10];
Here arr is of type int* but arr[0] will be of type int.
similarly, this->table[i] is of type Node and new Node returns Node*. Hence incompatible types. Correct line would be
this->table[i] = *new Node;
But, this line is unnecessary as the array of Nodes is already created and the memory is allocated. Using this line in the code will lead to a memory leak.
I'm trying to learn C++ and there is a small confusion I have.
The text which I am learning from tells me that if I want to delete a node of type const T& I should first create a new pointer of that node type, then delete it using the inbuilt C++ delete[]. However, what happens if I just set the link from the to-be-deleted node's previous element to the to-be-deleted node's next element? Something like:
*p = node.previous;
p-> next = node.next;
Or will this cause a memory leak?
I'm confused because I read somewhere else to never, ever delete pointers willy-nilly, but the example code I am working with has something along the lines of:
Node<T> *p = node-to-be-deleted;
delete p;
What is the best way to delete the node?
Assuming your node looks like this:
struct Node
{
Node* previous;
Node* next;
SomeType data;
};
Then:
*p = node.previous;
p-> next = node.next;
Then YES. This will cause a memory leak.
It also leaves p->next->prev pointing at the wrong node.
I'm confused because I read somewhere else to never, ever delete pointers willy-nilly, but the example code I am working with has something along the lines of:
Yes the best way is to "never delete pointers". But this has to go along with some context. You should not be deleting pointers manually because pointers should be managed by an objects that control their lifespan. The simplest of these objects are smart pointers or containers. But for this situation that would be overkill (as you are creating the container).
As you are creating the container (a list) you will need to do the management yourself (Note C++ already has a couple of lost types std::list for a list of values of type t or boost::ptr_list for a list of pointers to T). But it is a good exercise to try and do it yourself.
Here is an example on code review of a beginner making a list and the comments it generated:
http://codereview.stackexchange.com: Linked list in C++
I hope this helps in explains on how to create and delete objects.
Node* p = new Node; // This is how you allocate a node
delete p; // This is how you delete it
The delete[] operator should be used on dynamically allocated arrays:
Node* nodelist = new Node[ 4 ]; // nodelist is now a (dynamically allocated) array with 4 items.
delete[] nodelist; // Will delete all 4 elements (which is actually just one chunk of memory)
Deleting a Node directly only makes sense if Node implements a destructor to update the previous and next pointers of the surrounding Node instances, eg:
Node::~Node()
{
if (previous) previous->next = next;
if (next) next->previous = previous;
}
Node *p = node-to-be-deleted;
delete p;
Otherwise, you have to update the Node pointers before then deleting the Node in question, eg:
Node *p = node-to-be-deleted;
if (p->previous) p->previous->next = p->next;
if (p->next) p->next->previous = p->previous;
delete p;
With that said, the best approach is to no implement a linked list manually to begin with. In C++, use a std::list container instead, and let it handle these details for you.
void deleteNode( Node * p )
{
Node * temp = p->next;
p->data = p->next->data;
p->next = temp->next;
free(temp);
}
Heres something i did a few months ago.
template <class T>
T LinkedList<T>::remove(int pos)
{
if (pos < 1 || pos > size)
{
throw pos;
}
ListNode * temp;
if (pos == 1)
{
temp=head;
head = head->next;
}
else
{
int i=1;
ListNode * prev = head;
while(i<pos-1)
{
i++;
prev=prev->next;
}
temp = prev->next;
prev->next = (prev->next)->next;
}
--size;
return temp->item;
}
I'm trying to create an object in a function, but I am running into the problem that variable names have to be defined at runtime. Is there something I can do like with arrays that allows ne to dynamically create a variable in a function and preferably give it a different name from the one created when the function was called last?
***I'm working in C++
EDIT:
I can't give any code because I don't have any right now. All I have right now is pseudo code.
Basically, I'm trying to create a linked list, but the addNewItem() method that I want to use would require using the same method to create different objects.
EDIT:
Technically, we're not making a linklist, just more of a proof of concept to understand how they work.
EDIT: Here's the code:
#include "linklist.h"
#include <iostream>
using namespace std;
struct linklist
{
Student * obj;
linklist * next;
};
linklist * head;
int main()
{
}
void addStudent(char * newsdnt)
{
if(!head){
linklist * a = new linklist;
a->obj = new Student(newsdnt);
a->next = 0;
head = a;
return;
}else{
linklist * a = new linklist;
a->obj = new Student(newsdnt);
a->next = 0;
if(!head->next){
head->next = a; // Can only have one or two items in list
}
}
}
If you want a linked list - call new to create each new node and then add it to the list.
Smth like this:
void addStudent(char * newsdnt)
{
linklist* a = new linklist;
a.obj = new Student(newsdnt);
a.next = 0;
if( head == 0 ) {
head = a;
} else {
linklist* whereToAdd = head;
while( whereToAdd.next != 0 ) {
whereToAdd = whereToAdd.next;
}
whereToAdd.next = a;
}
}
The easiest way to build a (singly) linked list is to add the new item at the front:
linklist *head = 0;
...
a->next = head;
head = a;
...
If it is acceptable to add items at the tail in O(N) time, then you scan the list each time to find the end.
linklist head;
...
a->next = 0;
item = &head;
while (item->next != 0)
item = item->next;
item->next = a;
...
If you must add new items at the tail of the list in O(1) time, then keep a circular list, and a pointer to the tail of the list (so that tail->next is a pointer to the head of the list). (The previous list structures could be called 'open ended'.)
linklist root = { 0, &root };
linklist *tail = &root;
...
a->next = tail;
tail->next = a;
...
Beware: the termination conditions for iterating over the entire list (e.g. to find an item in the list) vary depending on the structure used (circular versus open-ended).
Caveat: untested code!
If you aren't sure what O(1) and O(N) means, then read up on 'Big O' notation.
I would suggest a vector:
#include <vector>
using namespace std;
void foo()
{
vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
cout << v[0] + v[1] << endl;
}
Assuming that you need N objects of some type T:Arrays are very much present in C++. So is the STL which provides you with a host of oppertunities. You need to define how you will want to access and use these objects -- that influences the choice of your container. But can you post some code so that our answers are a little less vague (and more helpful to you)?
I'm not exactly sure what you want but is sounds like you could use Multiset.
Please provide more details, and I might be able to provide more help.
For starters I would suggest you rename your linkedlist struct to node and add a new linked list struct that holds the head, and (maybe) current / tail pointers. You should then implement methods in this class / struct that will allow you to manipulate it.
What you're missing at the moment is a method that will traverse the list (recursively getting the next pointer until you're at the end) and return a pointer to the last element. Once you have that, you can set the next pointer of that element to your newly created object.