I have created a linked list class VW with a function Build to add nodes to the list. However, when I run the code to build my linked list, the Build function throws an "access violation" error. The error is thrown by the call tmp->NextObj() in the Build function.
If the object of class VW is newly created and the Build is called for the first time, then the condition if(tmp==NULL) in the Build function should be true, and hence the program should not enter the else section during the first call to Build. What am I missing here? Could you please help.
class VW
{
World_Obj *head;
public:
void Build(...);
};
void VW::Build(...)
{
World_Obj *newObj;
newObj = new World_Obj;
newObj->SetData(...);
newObj->SetNext(NULL);
World_Obj *tmp;
tmp = this->head;
if (tmp == NULL)
this->head = newObj;
else
{
while (tmp->NextObj() != NULL)
{
tmp = tmp->NextObj();
}
tmp->SetNext(newObj);
}
}
int main()
{
VW *g_w;
g_w = new VW;
/* Reading arguments from input file*/
g_w->Build(...);
}
The issue was the missing constructor in the class VW,
VW(){ head=NULL;}
Thanks all!
Here is a big problem:
tmp = this->head;
...
while (tmp->NextObj() != NULL)
{
tmp = tmp->NextObj();
}
tmp->SetNext(newObj);
...
delete tmp;
When the loop ends and after you do tmp->SetNext(newObj) then tmp will point to the second to last node in the list. Which you then promptly destroy by deleting it.
That means your list will now somewhere contain a node that no longer exist, and attempting to dereference it will lead to undefined behavior and most likely a crash.
The solution is simply to not delete tmp.
Related
I'm trying to implement a Singly linked list class in C++. I've overloaded the assignment operator to clone the list. The cloning itself seems to work fine, but the program crashes during deletion of the cloned list, which leads me to suspect if something's wrong during the copy procedure.
Any help is highly appreciated.
Here's the code for the overloaded = operator:
DLList& DLList::operator=(const DLList& iList)
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
return *this;
}
Here's the code for the push operation:
void DLList::push(int data)
{
Node *n = new Node;
n->data = data;
n->next = NULL;
//n->random = NULL;
n->next = _head;
_head = n;
//cout << "_head" <<_head->data<< "head->next" << (_head->next ? _head->next->data : 0)<<endl;
}
Here's the main code (where the crash happens) :
DLList *d = new DLList();
d->push(10);
d->push(20);
d->push(30);
d->push(40);
d->setRandom();
d->display("Original list"); // Displays the original list fine
DLList *d1 = new DLList();
d1 = d;
d1->display("Cloned list"); //Displays the cloned list fine
delete d; // works fine
delete d1; // Crashes here due to segmentation fault, invalid pointer access during delete called as part of destructor)
Code for destructor (if it helps):
~DLList()
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
}
you are not using the assignment operator actually! You are just copying the pointer to the other pointer.
Debugging your code (or just add traces) would have showed that
you were not calling your copy code
the addresses of d and d1 are the same
So when you delete the second list you delete the same address twice.
You don't really need new here:
DLList d;
d.push(10);
DLList d1 = d; // assignment is REALLY called
d1.display("Cloned list");
the objects will be deleted when you go out of scope of your variables
If you want to test in your context, keeping the new, change
d1 = d;
by
*d1 = *d;
to activate assignment operator.
Another advice: factorize your copy code so it is shared between assignment operator and copy constructor, and the deletion code should be shared between destructor and assignment operator (to avoid memory leaks when assigning twice): Not tested, don't flame me if it doesn't compile, just tell me I'll fix it, I'm already overanswering here :)
DLList& DLList::operator=(const DLList& iList)
{
destroy(); // or you'll get memory leaks if assignment done twice
copy(iList);
return *this;
}
DLList& DLList::DLList(const DLList& iList)
{
_head = NULL; // set _head to NULL in all your constructors!!
copy(iList);
}
~DLList()
{
destroy();
}
void DLList::copy(const DLList& iList) // should be private
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
}
void DLList::destroy() // private
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
_head = NULL; // calling destroy twice is harmless
}
d1 = d; is NOT copying DLList. Instead, you just make d1 point to the list that d pointing to. So, both d1 and d are pointing to the same list. At the end of your program, you will delete the list twice, and make your program crash.
If you wish to use the assignment operator, you need to dereference your pointers. See here:
DLList *d1 = new DLList();
d1 = d; // <------------- This line
d1->display("Cloned list"); //Displays the cloned list fine
On the highlighted line, you're setting the pointer d1 to point to the same location as d. This means that when you call delete at the end of your code, you're trying to delete the same object (d in this case) twice.
To fix your code, you should dereference your pointers:
DLList *d1 = new DLList();
*d1 = *d; // <------------- Note the dereference applied to BOTH lists.
d1->display("Cloned list"); //Displays the cloned list fine
Alternatively, you should avoid using pointers entirely if you can. For your trivial example you could simply create your objects directly.
Your problem is the statement
d1 = d;
which does a pointer assignment, and makes d1 point to the same object as d. The subsequent delete statements cause the same object (*d) to be released twice. That is undefined behaviour (of which one symptom is a crash like you describe).
The above also does not invoke DLLists copy constructor. If that is your intent, you need to do
*d1 = *d;
which makes the object pointed to by d1 a copy of the one pointed to by d. The two delete statements are also appropriate in this case.
I'm working on an assignment and there's a problem I'm stuck on. So I'm making a doubly linked list. I want a a delete function that will take item as argument, search for that argument in the list. when it has found the node which contains that item, I have to DELETE that node. I am aware of how I would change the previous and next pointers to the the nodes around that node. The problem that has been bugging me however, is that when I just change the next pointer of the node before it and the previous pointer of the node after it, like in the code below, the particular node will only be disconnected from the list but it will still remain in the freestore. How do I delete it from there so that the memory it is taking is also freed?
The following is the code I have. Please take a look:
template <class T>
void LinkedList<T>::deleteElement(T item)
{
ListItem<T> *curPtr;
curPtr = searchFor(item); // this function returns the pointer to the node which contains the item.
(curPtr->next)->prev = curPtr->prev;
(curPtr->prev)->next = tempPtr->next;
}
So you see, the curPtr is being disconnected, but I believe it still exists somewhere on the freestore. How do I get rid of it permanantly?
Could you make an erase_next() method for your ListItem type?
I have something like the following in a similar class. Hope it helps.
void erase_next() {
// ensure it is not the last item
if(this->next != nullptr) {
// create a temporary pointer
ListItem<T>* tmp = this->next
// link next to the next item to the next item and change the
// next items previous item to this item
this->next = this->next->next;
next->prev = this;
// delete the old next item
delete tmp;
}
}
In your function you could call it with something like the following. Thanks to #davmac edits have been made to delete the first item
template <class T>
void LinkedList<T>::deleteElement(T item)
{
ListItem<T> *curPtr = searchFor(item);
if(curPtr->prev == nullptr) {
curPtr->next->prev = nullptr;
delete curPtr;
} else {
curPtr->prev->erase_next()
}
}
Edit:
I played around with this again, and you should be able to optimize the erase_next() function with the following
void erase_next() {
if(this->next != nullptr) {
this->next = this->next->next
// We've already linked next so we can delete the handle
// with prev Note: this method is not possible with a
// single linked list and we would need the temp variable
delete this->next->prev
next->prev = this;
}
}
That way you don't have to declare a temp variable.
I've seen the some solutions to this in this website but none of them solved my problem.
I'm implementing an n-children, unbalanced tree type and the add operation gives me an exception.
The code is as follows:
struct Node {
// Just to initialize the parent node to zero, default constructor
Node(Node *parent = 0) : m_parent(parent) {
}
Node *m_parent;
vector<Node *> m_children;
GameBoard m_currentBoard;
};
Where the error is happening:
Node *tempNode = 0;
// Going through each of them to create new nodes
for (unsigned int i = 0; i < availableBoards.size() ; i++) {
// Create a new node
tempNode = new Node;
tempNode->m_parent = curNode;
tempNode->m_currentBoard.setBoard(availableBoards[i]);
// This is the line when program crashes
curNode->m_children.push_back(tempNode);
}
I have also tried declaring the tempNode inside the loop but it didn't help either.
I've checked through the watch from Visual Studio, curNode isn't NULL nor the tempNode.
Why am I getting this error?
Thanks for your answers.
OK the problem was destroying the object that was running the second code segment even before calling it. It was something like follows:
class A{
int *getAsdf();
int *asdf;
}
int main() {
A *newObj = new A;
delete newObj;
newObj->getAsdf();
}
I don't have a single clue as to how a method is called from an object that was deleted before. Error happened inside a function like getAsdf and even the parameters were valid. Can some-one explain?
I'm studying C++ on my own time, and writing a linked list to try and get the hang of it. I'm worried about the way I've come up to delete the object. It's a singly linked list. Here's the destructor:
template <typename T>
LinkedList<T>::~LinkedList()
{
Node<T> * current = this->first;
do {
Node * temp = current->next;
delete current; // THIS JUST MIGHT BE A TERRIBLE IDEA!!!
Node * current = temp; // new current-- might work with the current
// delete a line above
} while (current->next != 0); // need to leave this->last so that I don't
// delete it twice in the next line.
// Just realized I'm deleting this->first, then
// in the next line [implicitly] deleting it again!
//
delete this;
}
I create a pointer to the first node in the list, create a temporary pointer to the next node, delete the first pointer, create a new pointer with the same name, which then loops back. After it's done, it deletes the 'this' pointer.
I'm sure you can see why I'm worried with the way I create a new pointer with the same name as a deleted pointer.
Don't delete this in the destructor.
If Node is a template, then you need to write Node<T> in all of those definitions.
Don't redefine current, just assign it a new value.
Other than that, I don't see any other problems in this snippet.
Why not compile the code, try it, and see what happens? The worst thing that would happen would be that your program crashes and you have to figure out why.
Your code should basically work except that you need to test current in the while loop condition instead of current->next and it is redundant (and probably wrong) to write delete this in a destructor, and there are some more errors that Cat Plus Plus pointed out in his answer.
If you're trying to learn C++, then you should learn more of it to the point where you understand the mistakes you made here and are confident that the fixed code will work.
Here is my fixed version of the function:
template <typename T> LinkedList<T>::~LinkedList()
{
Node<T> * current = this->first;
while(current != 0) {
Node<T> * temp = current->next;
delete current;
current = temp;
}
delete this;
}
I don't see the question but I see lots of errors:
template <typename T>
LinkedList<T>::~LinkedList()
{
Node<T>* current = this->first; // you never check if this->first is 0
do {
Node * temp = current->next;
delete current; // THIS is not a problem
Node * current = temp; /* this line has no effect -
you define new variable and it disappears when reaches
the end of its scope next line */
} while (current->next != 0); /* 'current' is always 'this->first' but
even if you would assign it 'temp' like you intended few lines
above you never check if 'current' is 0 so you will
dereference 0 when you reach the end of the list */
delete this; /* this line is total nonsense
if your LinkedList is created with 'new LinkedList' then
you have infinite recursion (you call destructor from destructor)
otherwise you 'delete' pointer that you never 'new'-ed */
}
The correct code is this:
template <typename T>
LinkedList<T>::~LinkedList()
{
Node<T>* current = this->first;
while (current != 0)
{
Node<T>* temp = current->next;
delete current;
current = temp;
}
}
~LinkedList
{
//...
delete this;
}
delete this; in a destructor is like a code-suicide. Your object is already getting destructed and you are again destructing with delete this;. It's an undefined behavior. You can remove that. Rest of things look fine (assuming that this->first gives the head Node).
Edit: I missed that, you have redefined current. Remove that. (should be simply current = temp;)
I'm writing a program as an assignment for school and I though I had worked out all the bugs until I decided to call my copy constructor. The program is interactive (CLI) which basically has two moduals: a .h and .cpp file for the LList class and a .h and .cpp file for the structure of the program and also a 3rd cpp file just for main(). It is suppose to be a program for a hydropower engineering company (fake company) in which the LList nodes hold data for their annual water flow in a river(year and flow). Here is some insight on the class:
//list.h
struct ListItem {
int year;
double flow;
};
struct Node {
ListItem item;
Node *next;
};
class FlowList {
public:
FlowList();
// PROMISES: Creates empty list
FlowList(const FlowList& source);
// REQUIRES: source refers to an existing List object
// PROMISES: create the copy of source
~FlowList();
// PROMISES: Destroys an existing list.
FlowList& operator =(const FlowList& rhs);
// REQUIRES: rhs refers to an existing FlowList object
// PROMISES: the left hand side object becomes the copy of rhs
//....Other member functions
private:
// always points to the first node in the list.
Node *headM;
// Initially is set to NULL, but it may point to any node.
Node *cursorM;
//For node manipulation within interactive CLI
void copy(const FlowList& source);
void destroy();
I belive the memory leak or collision is taking place somewhere within the copy function but cant pin point where.
//list.cpp
FlowList::FlowList() : headM(0), cursorM(0) {}
FlowList::FlowList(const FlowList& source)
{
copy(source);
}
FlowList::~FlowList()
{
destroy();
}
FlowList& FlowList::operator =(const FlowList& rhs)
{
if (this != &rhs)
{
destroy();
copy(rhs);
}
return (*this);
}
//...more function definitions
void FlowList::copy(const FlowList& source)
{
if (source.headM == NULL)
{
headM = NULL;
cursorM = NULL;
return;
}
Node* new_node = new Node;
assert(new_node);
new_node->item.year = source.headM->item.year;
new_node->item.flow = source.headM->item.flow;
new_node->next = NULL;
headM = new_node;
Node* thisptr = new_node;
for(Node* srcptr = source.headM->next; srcptr != NULL; srcptr = srcptr->next)
{
new_node = new Node;
assert(new_node);
new_node->item.year = srcptr->item.year;
new_node->item.flow = srcptr->item.flow;
new_node->next = NULL;
thisptr->next = new_node;
thisptr = thisptr->next;
}
}
void FlowList::destroy()
{
Node* ptr = headM;
Node* post = headM->next;
while (ptr != NULL)
{
delete ptr;
ptr = post;
if (post)
post = ptr->next;
}
headM = NULL;
}
The program works fine if I create a FlowList object, fill it with data from a .dat file; i can then manipulate the data within the program (display, perform calculations, add to the list, remove from list and save data to file) but program crashes (segmentation fault) if I create another FlowList object (within main.cpp).
Any help would be really appreciated.
The initial thing I spot is that it looks like your destroy() function will always segmentation fault if the list is empty:
void FlowList::destroy()
{
Node* ptr = headM;
Node* post = headM->next;
//...
}
If the list is empty, headM is NULL and then you're trying to do headM->next which will always produce a segmentation fault in that case.
I think you might also have a memory leak in your copy constructor if you pass in an empty list. If you look at this code:
void FlowList::copy(const FlowList& source)
{
if (source.headM == NULL)
{
headM = NULL;
cursorM = NULL;
return;
}
//...
}
What if the current list contained 20 items and source is an empty list? You set the current list's headM and cursorM to NULL, but you never call delete on any of the nodes in the current list that you originally used new to create. You probably want to work your destroy() function somewhere into your copy constructor too (you did it for the operator= function).
The last thing I noticed is that you don't initialize cursorM for a non-empty list in your copy() function (#Akusete pointed that out as well). I think I'd recommend that at the beginning of your copy constructor, just initialize cursorM and headM to NULL just to cover your bases.
It looks like you're really close, I think you just really need to think through the boundary case of dealing with empty lists (both on the LHS and RHS) and you'll probably find most of these bugs. Good luck!