Seg fault when deleting temporary pointer - c++

I used gdb to find the exact line with the seg fault. It's noted within the dequeue function as a comment.
Here is the entire queue class.
I seg fault upon calling dequeue() when there are two objects and the sentinal within the queue.
template <typename T>
void Queue<T>::clear()
{
while(!isEmpty())
dequeue();
}
template <typename T>
void Queue<T>::enqueue(const T& x)
{
if(isEmpty())
{
Queue<T>* temp = new Queue<T>;
m_data = x;
m_next = temp;
return;
}
Queue<T>* temp = this;
while(temp->m_next != NULL)
{
temp = temp->m_next;
}
Queue<T>* node = new Queue<T>();
temp->m_data = x;
node->m_next = temp->m_next;
temp->m_next = node;
return;
}
template <typename T>
void Queue<T>::dequeue()
{
if(isEmpty())
return;
if(m_next != NULL)
{
Queue<T>* temp = m_next;
m_data = temp->m_data;
m_next = temp->m_next;
delete temp; //Seg fault here
}
return;
}
template <typename T>
const T& Queue<T>::front() const throw (int)
{
if(isEmpty())
throw 0;
return m_data;
}
template <typename T>
bool Queue<T>::isEmpty() const
{
return (m_next==NULL);
}
template <typename T>
int Queue<T>::size() const
{
int size = 0;
const Queue<T>* temp = this;
while(temp->m_next != NULL)
{
temp = temp->m_next;
size++;
}
return size;
}
Sorry, thought I'd already posted the Queue class:
template <typename T>
class Queue : public AbstractQueue<T> {
public:
Queue(){m_next = NULL;};
virtual void clear();
virtual void enqueue(const T& x);
virtual void dequeue();
virtual const T& front() const throw (int);
virtual bool isEmpty() const;
virtual int size() const;
~Queue(){
clear();
return;
};
private:
T m_data;
Queue* m_next;
};
And it inherits from this class:
template < typename T >
class AbstractQueue
{
public:
// Purpose: clears the queue
// Postconditions: the queue is now empty
// -- PURE VIRTUAL
virtual void clear() = 0;
// Purpose: enqueue an element into the queue
// Parameters: x is the item to add to the queue
// Postconditions: x is now the element at the end of the queue,
// -- PURE VIRTUAL
virtual void enqueue(const T& x) = 0;
// Purpose: dequeues
// Postconditions: the element formerly at the front of the queue has
// been removed
// Dequeueing from an empty Queue produces no errors, queue remains empty.
// -- PURE VIRTUAL
virtual void dequeue() = 0;
// Purpose: looks at the front of the queue
// Returns: a reference to the element currently in front of the queue
// Exception: if the queue is currently empty, throw SOMETHING!!
// -- PURE VIRTUAL
virtual const T& front() const = 0;
// Purpose: Checks if a queue is empty
// Returns: 'true' if the queue is empty
// 'false' otherwise
// -- PURE VIRTUAL
virtual bool isEmpty() const = 0;
// Purpose: Returns the size of a queue.
// Returns: the number of elements in the Queue
// -- PURE VIRTUAL
virtual int size() const = 0;
// ----------------
// Purpose: Destructor
// -- VIRTUAL
virtual ~AbstractQueue() {};
};

In this code:
Queue<T>* temp = m_next;
m_data = m_next->m_data;
m_next = m_next->m_next;
You don't check that m_next is non-null (if you're at the end of the list) so you start dereferencing the null pointer and all bets are off at that point.

To me, the following line inside enqueue() looks little strange.
Queue<T>* node = new Queue<T>();
It is creating a new Queue every time.
Could the intention be the following instead?
T * node = new T;

OK, instead of giving you a fish, I will teach you how to fish...
When you get segmentation fault it means that the operating system has detected a memory access error.
This usually happens in C/C++ when you play with pointers. pointers are very dangerous and have to be treated carefully.
How to detect where the problem occurs ?
Well, Linux is not very informative when your program receives SEGFAULT however, it gives you a lot of information. you just need to know how to "read" it.
The coredump, is a picture of the memory, stack and variables at the moment the segmentation fault occurred. to run it
gdb myapp core
where myapp is your application executable, and core is the coredump.
now you'll see something like:
GNU gdb 19991004
Copyright 1998 Free Software ���.�
Core was generated by `testit'.
Program terminated with signal 11, Segmentation fault.
Reading symbols from /usr/lib/libstdc++-libc6.1-1.so.2...done.
Reading symbols from /lib/libm.so.6...done.
Reading symbols from /lib/libc.so.6...done.
Reading symbols from /lib/ld-linux.so.2...done.
#0 0x823221a in main () at blabla.c:3
10 *i++;
it will show you exactly which line caused the fault.
If you want to know exactly how you got to that line, type bt
this will show you the backtrace, from your application main() until the actual fault, including parameters passed to the functions.
I think that once you'll know exactly where the segmentation fault occurred it will be much easier for you to solve it.
Few notes:
If coredump is not created.
type this in the console:
ulimit -c unlimited
You need to compile your program with -g to enable meaningful names of symbols in gdb.

Related

deleting a object by calling a method it belongs

I have been learning and playing around C++ (mostly, pointers and dynamic memory allocation) for few days and I tried to create a generic class for linked list.
The classes
#include <cstdint>
#define _LINKEDLIST_DEFAULT_MAX_SIZE 2147483647L
template <typename T>
class LinkedList;
template <typename T>
class LinkedListNode;
template <typename T>
class LinkedListNode final
{
private:
LinkedListNode<T> *nextNode{nullptr};
friend LinkedList<T>;
public:
T data{};
};
template <typename T>
class LinkedList final
{
private:
LinkedListNode<T> *firstNode{nullptr};
std::int32_t maxLength{};
std::int32_t currentLength{};
public:
LinkedList(std::int32_t max_size = _LINKEDLIST_DEFAULT_MAX_SIZE)
{
maxLength = max_size;
}
void addFirst(LinkedListNode<T> *nodePtr)
{
if (firstNode == nullptr)
{
firstNode = nodePtr;
return;
}
nodePtr->nextNode = firstNode;
firstNode = nodePtr;
}
void clerList()
{
// code of releasing occupied heap memory back
}
}
Main method
int main()
{
LinkedList<short> *head{new LinkedList<short>()};
LinkedListNode<short> *node1{new LinkedListNode<short>()};
LinkedListNode<short> *node2{new LinkedListNode<short>()};
node1->data = 1;
node2->data = 2;
head->addFirst(node1);
head->addFirst(node2);
return 0;
}
And this works as properly so far as variables in my debugger shows expected results.
But my issue is how could I write my clearList() method on LinkedList<T> class? I can traverse through LinkedListNode<T> objects and release their memory back calling delete(), but calling delete(this) from clearList() to release back the memory of LinkedList<T> object at first sounds like suiciding since it tries to delete the object which it belongs to. (Note that some simple validation logics have not yet been put into the code)
Do you have any ideas to make this happen :)

Getting a "SIGSEGV" segmentation fault and unsure why

My program requires me to create a binary search tree that is also a set. I've got up to inserting items into it and having that work correctly, but my issue comes when I'm attempting to get recursively get the size of the tree, aka how many nodes there are. Below is all the code that matters I believe.
struct SetNode
{
T data;
SetNode<T>* left;
SetNode<T>* right;
SetNode(const T& value);
};
//Set based on a BST
template <class T>
class MySet
{
private:
SetNode<T>* root;
public:
//constructor, insert function, "contains" function declared here
//get number of items contained
int size() const;
int sizeHelper(SetNode<T>* curNode) const;
}
template<typename T>
int MySet<T>::size() const {
if (root == nullptr)
return 0;
else
return this->sizeHelper(root);
}
template<typename T>
int MySet<T>::sizeHelper(SetNode<T>* curNode) const {
return 1 + sizeHelper(curNode->left) + sizeHelper(curNode->right);
}
The issue arises in main after I declare Set<string> setA and attempt to call size with setA.size(). From the debugger, I've seen that this causes the aforementioned SIGSEGV error. I can change the declaration of sizeHelper and even remove it if need be, but other than the code within it, size must remain as it is. Should sizeHelper be a non-member function? Removing the const doesn't work.
Your sizeHelper is a recursive function with no exit condition, you just keep reading the left and right fields from the node you're given, but you never check if they are nullptr. If you do pass nullptr, you have UB and possibly a segfault.
To avoid it you need to add an exit condition like so.
template<typename T>
int MySet<T>::sizeHelper(SetNode<T>* curNode) const {
if (curNode == nullptr) {
return 0;
}
return 1 + sizeHelper(curNode->left) + sizeHelper(curNode->right);
}

Nodes of a list being freed before usage

I have a one-dimensional template list that contains nodes, each node has a link to next node.
It works rather well on it's own, but not when it contains another linked list.
LinkedList and Node looks something like that:
template <class T>
class LinkedList
{
private:
Node<T>* pPreHead;
public:
LinkedList(void);
~LinkedList(void);
Node<T>* getHead(void);
int size();
void addElementToEnd(T& value);
void deleteNextNode(Node<T>* pNodeBefore);
}
template <class T>
class Node
{
private:
T value;
Node* next;
public:
Node();
Node* getNext();
Node* getValue();
void setNext(Node* nextElem);
void setValue(T elem);
};
Now for the task I need to use LinkedList>, which is filled via a loop.
It looks something like this:
ifstream fl;
fl.open("test1.in", std::ifstream::in);
while (fl.good())
{
string currentLine;
getline(fl, currentLine);
LinkedList<string> newDNA;
//newDNA being filled here so I skipped code
DNAStorage.addElementToEnd(newDNA);
//Place 1
}
//Place 2
Now if I insert some test output code in "Place 1" everything is fine, but when the loop enters new iteration newDNA variable gets freed and so is the pointer inside DNAStorage (which is LinkedList<LinkedList<string>> in question), and when I try to print anything in "Place 2" I get segmentation fault.
Unfortunately I can't use any other data structures since this is the kind of task I need to do.
My question is - how can this be fixed, so that it actually is not freed prematurely?
Edit:
Here's my code for AddElementToEnd(T& value):
template <class T>
void LinkedList<T>::addElementToEnd(T &value)
{
Node<T> *newtail = new Node<T>;
newtail.setNext(NULL);
newtail.setValue(value);
if(pPreHead == NULL)
{
pPreHead = newtail;
return;
}
Node<T> *tail = pPreHead;
while(tail.getNext() != NULL)
{
tail = tail.getNext();
}
tail.setNext(newtail);
}
The problem is that you are storing references to objects that are going out of scope, causing undefined behavior when you try and access them. Your LinkedList<string> newDNA gets created and destroyed with each iteration of the while loop, yet you pass a reference to be stored in DNAStorage list.
One solution would be to store a copy of each object (not reference) in the list when addElementToEnd() gets called.

Constructor and Destructor Declaration Syntax with Template Class

I am trying to make a queue implementing a linked list but am running into a compiler error. The error is coming from the overloaded assignment operator function on the line where I call the destructor (marked with an all-caps comment). I have a hunch it is a simple fix that has something to do with the syntax of my constructor/destructor declarations.
The error I am getting states the following code: error C2512: 'Queue<char>::Queue' : no appropriate default constructor available
It mentions no constructor, but the line it refers to is the one below where I am trying to call the destructor.
Thanks in advance for your help.
#ifndef QUEUE_H
#define QUEUE_H
#include <iostream>
using namespace std;
template <class Type>
class Queue // Create a Queue data structure implementing a linked list
{
private: // The private members
struct Cell // The Cell class will be the blueprints for each link in the list
{
Type data; // The information held by the cell
Cell* next; // The link to the next cell
};
Cell* first = NULL;
Cell* last = NULL;
public: // The public members
Queue(Type);
bool isEmpty();
void push(Type);
Type pop();
Queue<Type>& operator=(Queue<Type>&);
friend ostream& operator<<(ostream&, const Queue<Type>&);
~Queue();
};
template<class Type>
Queue<Type>::Queue(Type inputData) // Constructor that initializes the queue with a new cell that last and first point to
{
first = new Cell;
first->data = inputData;
first->next = NULL;
last = first;
}
template<class Type>
Queue<Type>& Queue<Type>::operator=(Queue<Type>& queue) // Overload "=" so that it performs a deep copy of a Queue object
{
if (!queue.isEmpty())
{
~Queue(); // HERE IS THE ERROR LINE
Cell* rhs = queue.first;
while (rhs != NULL)
{
push(rhs->data);
rhs = rhs->next;
}
}
return *this;
}
template<class Type>
Queue<Type>::~Queue() // Destructor that deallocates all of the memory used by the queue.
{
if (!isEmpty()) // We only need to deallocate the queue if it is non-empty
{
Cell *link = last;
while (link != NULL) // Until we reach the end of the queue, keep deleting each link
{
pop();
}
first = NULL;
last = NULL;
}
else // If the queue is already empty, let the user know
{
cout << "Cannot call destructor. The list is already empty.\n";
}
}
#endif
Check out this thread: Can i call destructor from its class method?. An easy way around this is to make a function to empty the queue, then call it from the destructor and assignment operator.
template<class Type>
void Queue<Type> empty(){
if (!isEmpty()) // We only need to deallocate the queue if it is non-empty
{
Cell *link = last;
while (link != NULL) // Until we reach the end of the queue, keep deleting each link
{
pop();
}
first = NULL;
last = NULL;
}
else // If the queue is already empty, let the user know
{
cout << "Cannot call empty. The list is already empty.\n";
}
}
template<class Type>
Queue<Type>& Queue<Type>::operator=(Queue<Type>& queue) // Overload "=" so that it performs a deep copy of a Queue object
{
if (!queue.isEmpty())
{
empty(); // Tada, no more error
Cell* rhs = queue.first;
while (rhs != NULL)
{
push(rhs->data);
rhs = rhs->next;
}
}
return *this;
}
template<class Type>
Queue<Type>::~Queue() // Deconstructor that deallocates all of the memory used by the queue.
{
empty();
}
This has nothing to do with template.
If you declare any constructor for your class, the compiler synthesized default constructor(i.e. the one that takes no arg) is deleted.
You have to define Queue() yourself.
BTW, a using directive in the global scope is not a good idea.
I guess you define a queue without parameter, like
Queue<char> quCh;
If you want to do this, you must define a constructor without parameter.
Queue();
or you must define your queue like this:
Queue<char> quCh('a');

Deleting an element from an empty queue?

I'm writing abstract data type of priority queue as a task for an university, which others are going to use. I have a function in my class dequeue, which deletes the first element in the queue and returns the data of this element. However when I try to delete an element from an empty queue, the program crashes. What should I do here ?
Here's the code if it helps:
#ifndef PRIORITYQUEUE_H
#define PRIORITYQUEUE_H
#include <iostream>
using namespace std;
const int max_queue_items = 1000;
template<class T>
struct node{
T data;
int priority;
node *next;
};
template<class T>
class PriorityQueue
{
public:
/*
Constructor that creates an empty queue.
*/
PriorityQueue(){
head = NULL;
size = 0;
}
/*
Adds an element to the queue.
Params:
data - data of the element
priority - priority of the element
*/
bool is_empty(){
if (size == 0){
return true;
}
return false;
}
bool is_full(){
if (size == max_queue_items){
return true;
}
return false;
}
/*
Adds an element to thq queue.
It gets inserted before the first element with
lower priority.
*/
void enqueue(T data, int priority){
node<T> * previous = NULL;
node<T> * now = head;
while (now != NULL && now->priority >= priority){
previous = now;
now = now->next;
}
node<T> * new_element = new node<T>;
new_element->data = data;
new_element->priority = priority;
new_element->next = now;
if (previous == NULL){
head = new_element;
} else {
previous->next = new_element;
}
size++;
}
/*
Removes the first element in the queue
*/
T dequeue(){
T data;
if (!is_empty()){
node<T> * now = head;
data = now->data;
head = head->next;
delete now;
size--;
}
return data;
}
/*
Returns the priority of the first element.
It's always the highest priority in the queue.
*/
int get_first_priority(){
return head->priority;
}
/*
Returns the data of the first element in the queue.
*/
T get_first_value(){
if (is_empty())
throw 0;
return head->data;
}
/*
Returns the number of elements in the queue.
*/
int get_size(){
return size;
}
/*
Deletes the whole queue from the memory.
*/
void flush(){
node<T> * now;
while (head != NULL){
now = head;
head = head->next;
delete now;
size--;
}
}
/*
Prints the whole queue following this format:
data(priority)
*/
void print(){
node<T> * now = head;
while (now != NULL){
cout << now->data << "(" << now->priority << ")" << endl;
now = now->next;
}
}
private:
node<T> * head; // Pointer to the head of the queue
int size; // Number of elements in the queue
};
#endif // PRIORITYQUEUE_H
This may or may not be the source of your problem, but I would definitely consider it an issue. In function dequeue() you are potentially returning an uninitialized variable (if T is not a class type) when is_empty() returns true:
T dequeue()
{
T data; // Uninitialized if T is not a class type
if (!is_empty())
{
node<T> * now = head;
//--------------------------------------------------------------
// This initialization is skipped when `is_empty()` returns true
data = now->data;
//--------------------------------------------------------------
head = head->next;
delete now;
size--;
}
return data;
}
Depending on what you do with the value returned by this function and on the type of T, your program might have Undefined Behavior (I can imagine T being a pointer type that you later dereference).
You may want to change the first line of the function into:
T data = T();
Which enforces value-initialization of your data object. If T is a class type, the default constructor will be invoked. Otherwise, data will be zero-initialized.
The function which calls dequeue() should then check the returned value before using it (or better, call is_empty() on the queue to check it is not empty before trying to pop a value from it).
You may even consider throwing an exception when dequeue() is invoked and the queue is empty:
T dequeue()
{
if (is_empty())
{
// Requires including the <stdexcept> standard header
throw std::logic_error("Queue is empty");
}
node<T> * now = head;
T data = now->data;
head = head->next;
delete now;
size--;
return data;
}
Clients are now responsible for making sure that dequeue() is never called on an empty queue (or they shall wrap calls to dequeue() into a try/catch block to handle the possibly thrown exception.
Another possibility is returning a bool to your client indicating whether the value was successfully popped, possibly assigning the popped element to an argument passed by reference:
bool dequeue(T& data)
{
if (is_empty())
{
return false;
}
node<T> * now = head;
data = now->data;
head = head->next;
delete now;
size--;
return true;
}
This way, the client is responsible for checking the result of the function. If the function returns false, the data variable will be initialized to whatever the client initialized it to. Responsibilities for handling error situations is again transferred to the client.
I think there are some issues.
First and most important, there is no destructor for the class. And if not all elements are dequeued in your program there will be a memory leak. Write the destructor or use smart pointer instead of the raw one.
Second, as #Andy Prowl(btw who knows how to # people in post like twitter?) said, uninitialized local variable should be considered. And T data = T() works well both for built-in and custom types.
Third, I think there is a capacity restriction max_queue_items for the queue but there is no corresponding code for the enqueue part.
Even though, I don't think all these flaws could cause a serious crash in normal case. Maybe the problem occurs in your code invokes the class and the incorrect processing for uninitalized return value leads to a crash.
The only potential problem I see in you dequeue is that you are creating a temporary variable of the unknown type T. If you are storing data of a type with no default constructor in your priority queue, you are going to have a problem when your dequeue calls and tries to default construct that variable.
If this is the case, I would suggest that you re-work your priority queue to hold pointers to the template type rather than the data itself.