I'm getting segmentation fault error with the follow main function. The header file has a linked list implementation with an iterator class and different testing members.
The thing is that the segmentation fault error shows up on a certain compilers and goes away on other. I tried using GDB to debug for any errors, but the program executes fine.
This is really bugging me as I cannot find the reason this would throw a segmentation fault error.
Any help is greatly appreciated.
EDIT: I noticed that with this updated main, the logic is flawed and does not insert the node at the specified location. So, I'll have to do some more debugging to figure out the issue.
It seems the else if block inside insert() is executed instead of the else block.
Main.cpp
#include <iostream>
#include "List.h"
int main(){
List<double> l;
l.push_back(1.1);
l.push_back(2.2);
l.insert(l.begin()++, 3.3);
l.printList();
}
List.h
#include <cstdint>
#include <iostream>
#include <memory>
template<typename T>
class List
{
public:
class Node {
public:
Node(T value) : value_(value) {}
Node(T value, Node* prev, Node* next) : value_(value), prev_(prev), next_(next) {}
T value_;
Node* next_;
Node* prev_;
};
Node* head_;
Node* tail_;
//! An iterator over the list
class iterator
{
public:
Node* iNode;
iterator(Node* head): iNode(head){ }
~iterator() {}
T& operator*() {
return iNode -> value_;
}
iterator& operator++() {
iNode = iNode->next_;
return *this;
}
iterator operator++(int ignored) {
iNode = iNode->next_;
return *this;
}
iterator& operator--() {
iNode = iNode->prev_;
return *this;
}
//! Is this iterator pointing at the same place as another one?
bool operator== (const iterator& it) const {
return this->iNode == it.iNode;
}
//! Is this iterator pointing at a different place from another?
bool operator!= (const iterator& it) const {
return this->iNode != it.iNode;
}
};
//! Default constructor
List() :tail_(nullptr) {}
void push_back_node(T value)
{
Node* newnode = new Node(value, tail_, nullptr); //make and link new tail node
if (tail_)
{
tail_->next_ = newnode; // link in new node
}
else
{
head_ = newnode;
}
tail_ = newnode; // update tail
}
//! Copy constructor
List(const List& lst) : head_(nullptr), tail_(nullptr)
{
Node* cur = lst.head_; //get first source item.
while (cur) // if there is a source item to copy
{
push_back_node(cur->value_); // stick the item on the end of this list
cur = cur->next_; // get next source item
}
}
void clear()
{
while (head_)
{
delete std::exchange(head_, head_->next_);
}
tail_ = head_;
}
//! Copy assignment operator
List& operator= (const List& list_copy) {
List tmp(list_copy);
clear();
std::swap(*this, tmp);
return *this;
}
//! Move constructor
List(List&& move) {
head_ = std::move(move.head_);
tail_ = std::move(move.tail_);
}
////! Move assignment operator
List& operator= (List&& list) {
head_ = std::move(list.head_);
tail_ = std::move(list.tail_);
return *this;
}
//! Destructor
~List() {}
//
// Accessors:
//
//! How many elements are in this list?
size_t size() const {
size_t size = 0;
auto temp = head_;
while (temp != nullptr)
{
size++;
temp = temp->next_;
}
return size;
}
//! Is this list empty?
bool empty() const {
return tail_ == nullptr && head_ == nullptr;
}
//! Get an iterator to the beginning of the list
iterator begin() {
return List<T>::iterator(head_);
}
//! Get an iterator just past the end of the list
iterator end() {
return List<T>::iterator(tail_);
}
//
// Mutators:
//
//! Copy an element to the front of the list
void push_front(const T& value) {
Node* node = new Node(value);
if (head_ == nullptr) {
head_ = node;
}
else {
node->next_ = head_;
head_ = node;
}
}
//! Move an element to the front of the list
void push_front(T&& value) {
Node* node = new Node(value);
if (head_ == nullptr) {
head_ = node;
}
else {
node->next_ = head_;
head_ = node;
}
}
//! Copy an element to the back of the list
void push_back(const T& value) {
Node* node = new Node(value);
if (tail_) {
tail_->next_ = node;
tail_ = tail_->next_;
}
else {
head_ = node;
tail_ = head_;
}
}
//! Add an element to the back of the list
void push_back(T&& value) {
Node* node = new Node(value);
if (tail_) {
tail_->next_ = node;
tail_ = tail_->next_;
}
else {
head_ = node;
tail_ = head_;
}
}
iterator insert(iterator position, const T& value) {
Node* newNode = new Node(value);
if (position == List<T>::iterator(head_)) {
newNode->next_ = head_;
head_ = newNode;
}
else if (!position.iNode->next_) {
position.iNode->next_ = newNode;
}
else {
Node* curr = head_;
while (curr->next_ != position.iNode)
{
curr = curr->next_;
}
newNode->next_ = curr->next_;
curr->next_ = newNode;
}
return position;
}
void printList() const{
auto node = head_;
while (node != nullptr)
{
std::cout << node -> value_ << " ";
node = node->next_;
}
}
iterator insert(iterator position, T&& value){
Node* newNode = new Node(value);
if (position == List<T>::iterator(head_)) {
newNode->next_ = head_;
head_ = newNode;
}
else if (!position.iNode->next_) {
position.iNode->next_ = newNode;
}
else {
Node* curr = head_;
while (curr->next_ != position.iNode)
{
curr = curr->next_;
}
newNode->next_ = curr->next_;
curr->next_ = newNode;
}
return position;
}
//! Remove an element from an arbitrary location
void erase(iterator it) {
Node* temp = it.iNode->next_;
// Copy data of the next node to current node
it.iNode->value_ = it.iNode->next_->value_;
// Perform conventional deletion
it.iNode->next_ = it.iNode->next_->next_;
free(temp);
}
};
free(temp);-- Undefined behavior. Do not usefreewith memory allocated withnew. Why would you reach for aCdeallocation function, knowing that you are writing C++ code?bool operator != (const iterator& it) const-- Prefer writing it in terms of the existingoperator ==. i.e.return !(iNode == it.iNode);