Does anyone have suggestions on how to improve this?
Specifically:
- Am I passing and returning references correctly to prevent unnecessary copying?
- Am I using destructors and the delete keyword correctly to prevent memory leaks?
- Am I throwing exceptions correctly?
Also, just wondering whether it would be possible, when inserting an element, to just declare a node as
list_node_generic node;
instead of the
list_node_generic* node = new list_node_generic();
Is this doable? If it is, is it encouraged or discouraged and why?
#ifndef list_generic_hpp
#define list_generic_hpp
#include <iostream>
namespace ds{
template <typename T>
class list_generic{
private:
class list_node_generic{
private:
list_node_generic* prev;
list_node_generic* next;
T data;
public:
list_node_generic(){
prev = nullptr;
next = nullptr;
}
~list_node_generic(){
delete next;
delete prev;
}
//Get Functions.
list_node_generic* get_prev(){
return prev;
}
list_node_generic* get_next(){
return next;
}
T& get_data(){
return data;
}
//Set Functions.
void set_prev(list_node_generic* p){
prev = p;
}
void set_next(list_node_generic* n){
next = n;
}
void set_data(T& d){
data = d;
}
};
list_node_generic* first;
list_node_generic* last;
int length;
public:
list_generic(){
list_node_generic* dummy = new list_node_generic();
first = dummy;
last = dummy;
length = 0;
}
list_generic(list_generic& other){
list_node_generic* dummy = new list_node_generic();
first = dummy;
last = dummy;
length = 0;
list_node_generic* current = other.first->get_next();
for (int i = 0; i < other.length; ++i){
append(current->get_data());
current = current->get_next();
}
}
list_generic operator=(list_generic& other){
list_generic replacement = (*new list_generic(other));
return replacement;
}
int size(){
return length;
}
bool empty(){
if (length == 0){
return true;
}
else{
return false;
}
}
void print(){
list_node_generic* current = first;
cout << "{";
for (int i = 0; i < length - 1; ++i){
current = current->get_next();
cout << current->get_data() << ", ";
}
current = current->get_next();
cout << current->get_data() << "}";
}
void insert(int index, T element){
if (index > length){
throw "Error: Index goes out of bounds.";
}
list_node_generic* node = new list_node_generic();
node->set_data(element);
if(index == length){
last->set_next(node);
node->set_prev(last);
last = node;
++length;
return;
}
list_node_generic* current = first->get_next();
for (int i = 0; i < index; ++i){
current = current->get_next();
}
node->set_prev(current->get_prev());
node->set_next(current);
current->get_prev()->set_next(node);
current->set_prev(node);
++length;
return;
}
void prepend(T element){
insert(0, element);
}
void append(T element){
insert(length, element);
}
T& get(int index){
if (empty()){
throw "Error: List is Empty... returning -1";
}
int real_index = index % length;
list_node_generic* current = first->get_next();
for (int i = 0; i < real_index; ++i){
current = current->get_next();
}
return current->get_data();
}
T& front(){
if (empty()){
throw "Error: List is empty...";
}
return first->get_next()->get_data();
}
T& back(){
if (empty()){
throw "Error: List is Empty... returning -1";
}
return last->get_data();
}
int search(T element){
if (empty()){
return -1;
}
list_node_generic* current = first;
for (int i = 0; i < length; ++i){
if (current->get_data() == element){
return i;
}
current = current->get_next();
}
std::cout << endl << element << " is not in the list" << endl;
return -1;
}
void remove(int index){
if (index >= length || index < 0){
return;
}
list_node_generic* current = first->get_next();
if (index == length - 1){
last = last->get_prev();
current = last->get_next();
current->get_prev()->set_next(nullptr);
length--;
return;
}
for (int i = 0; i < index; ++i){
current = current->get_next();
}
current->get_prev()->set_next(current->get_next());
current->get_next()->set_prev(current->get_prev());
length--;
return;
}
void pop_front(){
if(empty()){
return;
}
remove(0);
}
void pop_back(){
if (empty()){
return;
}
remove(length - 1);
}
~list_generic(){
}
};
}
#endif