Right now I'm working on a LinkedList project, with the clear method acting very strangely at the moment:
template <class Elm>
void LinkedSortedList<Elm>::clear() {
if (head != NULL) {
LinkedNode<Elm>* currentNode = head;
LinkedNode<Elm>* nextNode;
if (head->next != NULL) {
nextNode = head->next;
}
while (currentNode != NULL) {
nextNode = currentNode->next;
delete currentNode;
currentNode = nextNode;
}
head = NULL;
}
}
Everything appears to work properly until the line
nextNode = currentNode->next;
where both currentNode's and nextNode's values are switched to two completely different, extremely large values. Before that line, both variables have the proper values in them. When
delete currentNode;
is called in the next line, I immediately get a segfault, even though it doesn't look like the address of the node was changed in any way.
Is there anything that might be causing the pointers to point to two completely different places all of the sudden?
EDIT: Here's the LinkedNode class,
#ifndef _LinkedNodeClass_
#define _LinkedNodeClass_
#include <iostream>
using namespace std;
template <class Elm> class LinkedNode {
public:
Elm value; // The data value
LinkedNode *next; // Pointer to the next node
// Simple inline constructor: initialize values
LinkedNode(Elm newval = 0, LinkedNode* newptr = NULL)
{value = newval; next = newptr;}
~LinkedNode() {delete &next;}
// Inline print function: print the node's value
void print() {cout << value;}
};
#endif
Is there anything that might be causing the pointers to point to two completely different places all of the sudden?
Yes! If you don't have LinkedNode<T>::next initialized to NULL correctly in the class constructors or assignment operators, they might hold an uninitialized or invalid value. Many compilers use special values to indicate uninitialized pointers in debug version.
This might also happen for 'dangling' pointers that have been already deleted earlier. This might well be the case, because in your destructor you are already deleting the next pointer:
~LinkedNode() {delete &next;}
Thus next will be invalid in the next iteration step in the clear() function. Even worse, the syntax you are using is valid, but semantically wrong here: You are trying to delete the address where the next pointer variable itself lives (that certainly never was allocated with new).
Related
I have a problem with the application crashing at the line of code where if(!head) is being referenced inside the function: insertNode(). head and tail are class members of type node*. It looks like, I am missing something in the way the class members: head, tail are initialized..
This is the runtime error: "Unhandled exception at 0x00245246 in SLinkedlist_array.exe: 0xC0000005: Access violation reading location 0x00000000."
slinkedlist.h:
typedef struct node
{
int value;
struct node* next;
} node;
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head, tail;
};
slinkedlist.cpp:
bool slinkedlist::insertNode(int value, int aftNodeVal)
{
int toinsertval = value;
int searchkey = aftNodeVal;
bool retval = false;
// If it's a new linked list
if(!head) // THIS IS WHERE THE APPLICATION CRASHES!
{
node* head = new node;
head->value = toinsertval;
head->next = NULL;
return true;
}
else //It's not a new list
{
while(head->next != NULL)
{
//some more code here...
}
}
return retval;
}
void slinkedlist::displayList()
{
while(!head)
{
do
{
cout << head->value << " " ;
head = head->next;
}
while(head->next != NULL);
}
//return void;
}
main.cpp:
int main()
{
slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();
while(1);
}`
The answer is simple: you have null-pointer dereference here:
slinkedlist *s1 = NULL;
s1->insertNode(4, -1);
s1->displayList();
That's what exactly the system tells to you: "Access violation reading location 0x00000000"
Solution can be like:
slinkedlist *s1 = new slinkedlist;
s1->insertNode(4, -1);
s1->displayList();
delete s1;
Or like this (why not to use just an object on the stack?):
slinkedlist s1;
s1.insertNode(4, -1);
s1.displayList();
Or more C++ way (if you NEED a pointer):
auto s1 = make_unique<slinkedlist>(); // s1 is a std::unique_ptr<slinkedlist>
s1->insertNode(4, -1);
s1->displayList();
slinkedlist *s1 = NULL;
defines a pointer to a slinkedlist and DOES initialize it Unfortunately it initializes it to NULL, a safe parking address where (usually) no object are allowed to exist. For the vast majority of CPUs (every CPU I've ever worked on) accessing this dead zone around NULL will crash the program, making it much easier to detect bugs.
There is no need for a pointer here. If you don't need pointer, don't use one. Your life will be much easier.
int main()
{
slinkedlist s1; // default initializes
s1.insertNode(4, -1);
s1.displayList();
while(1); // rethink this. If you want to hold a program open to see the output
// while debugging, place a breakpoint in the debugger.
}
Default initializing of s1 alone will not help you because it will do the absolute minimum work to initialize its member variables, and in the case of a pointer the minimum work is to do nothing and leave head and tail uninitialized and pointing (sort of. tail is NOT a pointer) to an indeterminate location. Because you aren't also asking about the compiler error you should get from assigning NULL to tail, the program is clearly not initializing tail and I'll assume the slinkedlist constructor doesn't do much.
Side note: If you have a constructor or destructor that don't do anything (and don't need to do anything) leave them out and let the compiler generate the appropriate code. Code that does not exist (and doesn't need to exist) has no bugs.
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head, tail; // the * only applies to head.
};
could be
class slinkedlist
{
public:
//ctor, dtor, insertNode(int, int), displayList()
private:
node* head = nullptr;
node* tail = nullptr;
};
if you are compiling to recent (2011 or newer) C++ Standards. You won't need a constructor, the work is done for you with the default assignments. You will still need a destructor along with a copy constructor and an assignment operator to satisfy The Rule of Three.
In older C++ Standards you need to make the constructor smarter
class slinkedlist
{
public:
slinkedlist(): head(NULL), tail(NULL)
{
}
//dtor, insertNode(int, int), displayList()
private:
node* head; // I recommend splitting the definitions up. It makes the code easier
// to read and makes it harder to make mistakes.
node* tail;
};
You will still need a destructor, a copy constructor, and an assignment operator.
Note that this also applies to node. If you dynamically allocate a node and do not explicitly set next to a value, you won't know where next points, and all of the tests like
while(head->next != NULL)
will fail horribly.
I need to write a program that takes an instance of a linear linked list and removes all of the items in the list except for the last two items. I'm doing this in c++ using classes, so I'll have 3 files: main.cpp, list.h, and list.cpp. There can be no loops: I can use multiple functions but the traversal part has to be recursive.
I thought about it and what I concluded is this: I'll have to have one public function that I can call from main which will take no arguments, called void lastTwo(). I'll have another private function called node* lastTwo(node *& current, node *& tail) which will be called by lastTwo(), and it will traverse the list recursively and delete the nodes it touches until it reaches the second to last node in the list, and then it will return the address of that node.
Then, when it returns the address of the second to last node in the list, the public function lastTwo() will catch that address and set head equal to it.
The problem I'm having is that I need to do this in vi and compile and run from the command line, and I'm getting a segmentation fault even though I drew a pointer diagram and can't find a problem with my code.
I'm working on this on the student server at my university, and all of the implementation of the data structure except for these two functions have been written by my instructors, so they're all solid. Also, every time you run the a.out file, they've written it to generate a new, random, non-empty linked list, of at least 5 nodes.
I think the problem is related to the function having the return type "node*" , because I tried doing this in visual studio as well and it wouldn't let me have functions of type node*. But, I know that when you don't use classes and just put everything in one file, functions of type node* work.
Here is my list.h:
#include<iostream>
struct node
{
int data;
node* next;
};
class list
{
public:
// these functions were already written by the school and included in the .o file
list();
~list();
void build();
void display();
// my functions
void lastTwo();
private:
node* head;
node* tail;
node* lastTwo(node *& current, node *& tail);
}
And list.cpp:
void list::lastTwo(){
node* current = head;
node * newHead = lastTwo(current, tail);
head = newHead;
delete newHead;
head->next = tail;
}
node* lastTwo(node *& current, node *& tail){
if(current->next == tail){
return current;
}
else if(current->next != tail){
node* temp = current;
current = current->next;
temp->next = NULL;
delete temp;
lastTwo(current, tail);
}
return NULL;
}
Any ideas on what might be the problem, and what the correct way to do this is, would be really appreciated! Thank you
Your problem happens when your recursion unwinds. Most of the calls to lastTwo happen in the else if. That base case is the if which returns current, but the call to lastTwo which triggered the base case is always going to return NULL when the else if ends.
Imagine this is your stack when the base case is reached:
lastTwo // Base case, returns current, but the call below this doesn't do anything with it.
lastTwo // returns null
...
lastTwo // returns null
That NULL is used by the other lastTwo and you get your seg fault.
You might use the following:
void list::lastTwo() {
// Stop work with less than 2 items
if (head == nullptr // 0 items
|| head == tail // 1 item
|| head->next == tail) { // 2 items
return;
}
// pop_front()
auto* next = head->next;
delete head;
head = next;
// loop
lastTwo();
}
Hello I am trying to use pointers and learning the basics on unique pointers in C++. Below is my code I have commented the line of code in main function. to debug the problem However, I am unable to do so. What am I missing ? Is my move() in the insertNode() incorrect ? The error I get is below the code :
#include<memory>
#include<iostream>
struct node{
int data;
std::unique_ptr<node> next;
};
void print(std::unique_ptr<node>head){
while (head)
std::cout << head->data<<std::endl;
}
std::unique_ptr<node> insertNode(std::unique_ptr<node>head, int value){
node newNode;
newNode.data = value;
//head is empty
if (!head){
return std::make_unique<node>(newNode);
}
else{
//head points to an existing list
newNode.next = move(head->next);
return std::make_unique<node>(newNode);
}
}
auto main() -> int
{
//std::unique_ptr<node>head;
//for (int i = 1; i < 10; i++){
// //head = insertNode(head, i);
//}
}
ERROR
std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
Aside from other small problems, the main issue is this line:
return std::make_unique<node>(newNode);
You are trying to construct a unique pointer to a new node, passing newNode to the copy constructor of node. However, the copy constructor of node is deleted, since node contains a non-copyable type (i.e. std::unique_ptr<node>).
You should pass a std::move(newNode) instead, but this is problematic since you create the node on the stack and it will be destroyed at the exit from the function.
Using a std::unique_ptr here is a bad idea in my opinion, since, for example, to print the list (or insert into the list), you need to std::move the head (so you lose it) and so on. I think you're much better off with a std::shared_ptr.
I was having the same problem and indeed using a shared_ptr works.
Using the smart pointer as an argument in the function copies the pointer (not the data it points to), and this causes the unique_ptr to reset and delete the data it was previously pointing at- hence we get that "attempting to reference a deleted function" error. If you use a shared_ptr this will simply increment the reference count and de-increment it once you are out of the scope of that function.
The comments in the answers above suggest that using a shared_ptr is baseless. These answers were written before the C++17 standard and it is my understanding that we should be using the most updated versions of the language, hence the shared_ptr is appropriate here.
I don't know why we have to expose node type to user in any case. Whole thingamajig of C++ is to write more code in order to write less code later, as one of my tutors said.
We would like to encapsulate everything and leave no head or tail (pun intended) of node to user. Very simplistic interface would look like:
struct list
{
private:
struct node {
int data;
std::unique_ptr<node> next;
node(int data) : data{data}, next{nullptr} {}
};
std::unique_ptr<node> head;
public:
list() : head{nullptr} {};
void push(int data);
int pop();
~list(); // do we need this?
};
The implementation does something what Ben Voigt mentioned:
void list::push(int data)
{
auto temp{std::make_unique<node>(data)};
if(head)
{
temp->next = std::move(head);
head = std::move(temp);
} else
{
head = std::move(temp);
}
}
int list::pop()
{
if(head == nullptr) {
return 0; /* Return some default. */
/* Or do unthinkable things to user. Throw things at him or throw exception. */
}
auto temp = std::move(head);
head = std::move(temp->next);
return temp->data;
}
We actually need a destructor which would NOT be recursive if list will be really large. Our stack may explode because node's destructor would call unique_ptr's destructor then would call managed node's destructor, which would call unique_ptr's destructor... ad nauseatum.
void list::clear() { while(head) head = std::move(head->next); }
list::~list() { clear(); }
After that default destructor would ping unique_ptr destructor only once for head, no recursive iterations.
If we want to iterate through list without popping node, we'd use get() within some method designed to address that task.
Node *head = list.head.get();
/* ... */
head = head->next.get();
get() return raw pointer without breaking management.
How about this example, in addition to the sample code, he also mentioned some principles:
when you need to "assign" -- use std::move and when you need to just traverse, use get()
I am writing a function to delete the last node in a linked list. This is what I have, and other code I've found online searching for a solution is very similar (I have found several), but when I execute it it creates some sort of infinite loop when deleting the last element of a linked list (it deletes other elements just fine though).
Here is the code I imagine is causing a problem:
void delete_final(Node* head){
if(head == NULL) {
return; }
if(head->next == NULL) {
delete head;
head = NULL;
return;
}
//other code
}
I imagine it's an issue with the memory (particularly after the delete head; statement), but I'm really stuck and would appreciate any help or an explanation for why this doesn't work (I possibly don't have a very good understanding of pointers and memory in C++, I'm just starting with it)
Here is my Node code for reference:
struct Node {
int key;
Node* next;
};
Thanks for any help!
Original code:
void delete_final(Node* head){
if(head == NULL) {
return; }
if(head->next == NULL) {
delete head;
head = NULL;
return;
}
//other code
}
The "other code" is not specified, but if the list has exactly one node then the above code will
delete that first node, and
update the local pointer head, which doesn't update the actual argument since it was passed by value.
As a result the calling code will be left with a dangling pointer in this case, a pointer pointing to a destroyed object, or to where such an object once was. Any use of such a pointer is Undefined Behavior. It might appear to work, or crash, or just silently cause dirty words tattoo to appear on your forehead – anything…
One fix is to pass the first-pointer by reference:
void delete_final(Node*& head){
if(head == nullptr) {
return; }
if(head->next == nullptr) {
delete head;
head = nullptr;
return;
}
//other code
}
A nice helper function for dealing with linked lists, is unlink:
auto unlink( Node*& p )
-> Node*
{
Node* const result = p;
p = p->next;
return result;
}
The implementation is perhaps a bit subtle, but all you need to remember to use it is that it updates the pointer you pass as argument, which should be either a first-node pointer or a next pointer in the list, and returns a pointer to the unlinked node.
So e.g. you can do
delete unlink( p_first );
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;)