I've decided to rewrite the standard library list in a smaller version. This is similar to another question of mine, where my main concern is memory management. I allocate a new array each time the user wants to modify the list. I want to know if there are any memory leaks that I need to plug. I've been liberal using delete[]
, but I need to know I've covered all my bases.
As always, best practices and other improvements are always welcome and appreciated.
#include <iostream>
#include <initializer_list>
template<class T>
class list {
private:
size_t length = 0;
T* elements = nullptr;
/**
* Determines if there will be an out of bound error. If so, handles
* it nicely and displays the range of acceptable integers allowed.
*
* @param position The index passed by the user.
*
* @return (void).
**/
void checkRangeError(const int& position) const {
if (position < 0 || position >= this->length) {
std::cout << "error: (position) parameter needs to be in range [0, " << this->length << ")" << std::endl;
exit(1);
}
}
public:
list() {}
list(std::initializer_list<T> args) {
for (auto arg : args) {
this->append(arg);
}
}
~list() { delete[] this->elements; }
// Capacity Functions //
/**
* Determines if the current list is empty.
*
* @return (bool) True if empty, False otherwise.
**/
bool empty(void) const { return this->length != 0; }
/**
* Returns the current length of the list.
*
* @return (size_t) Length of list.
**/
size_t size(void) const { return this->length; }
// Element Access Functions //
/**
* Returns the element at the front of the list. Does not pop, but
* simply returns the value.
*
* @return (T) First item in the list.
**/
T front(void) const { return this->elements[0]; }
/**
* Returns the element at the end of the list. Does not pop, but
* simply returns the value.
*
* @return (T) Last item in the list.
**/
T back(void) const { return this->elements[this->length - 1]; }
// Modifier Functions //
/**
* Adds an element to the end of the list. Grows the list size by one.
*
* @param value Element to add to the list.
*
* @return (void).
**/
void append(const T& value) {
if (this->length == 0) {
this->elements = new T[1];
this->elements[this->length++] = value;
return;
}
T* previous = new T[this->length];
for (int i = 0; i < this->length; i++)
previous[i] = this->elements[i];
this->elements = new T[++this->length];
for (int i = 0; i < this->length; i++)
this->elements[i] = previous[i];
this->elements[this->length - 1] = value;
delete[] previous;
}
/**
* Inserts an element at the given position. Shifts every element after down one.
*
* @param position Index to place value.
* @param value Element to add to list.
*
* @return (void).
**/
void insert(const int& position, const T& value) {
this->checkRangeError(position);
T* previous = new T[this->length];
if (position == 0) {
for (int i = 0; i < this->length; i++)
previous[i] = this->elements[i];
this->elements = new T[++this->length];
this->elements[0] = value;
for (int i = 1; i < this->length - 1; i++)
this->elements[i] = previous[i];
delete[] previous;
return;
}
for (int i = 0; i < this->length; i++)
previous[i] = this->elements[i];
this->elements = new T[++this->length];
for (int i = 0; i < position; i++)
this->elements[i] = previous[i];
this->elements[position] = value;
for (int i = position; i < this->length - 1; i++)
this->elements[i + 1] = previous[i];
delete[] previous;
}
/**
* Replaces the value at the given position with the new value.
*
* @param position Index to replace value.
* @param value New element to place in list.
*
* @return (void).
**/
void replace(const int& position, const T& value) {
this->checkRangeError(position);
this->elements[position] = value;
}
/**
* Erases the value at the given position, shrinking the size of the list by one.
*
* @param position Index to erase value.
*
* @return (void).
**/
void erase(const int& position) {
this->checkRangeError(position);
T* previous = new T[this->length];
for (int i = 0; i < this->length; i++)
previous[i] = this->elements[i];
this->elements = new T[--this->length];
for (int i = 0; i < position; i++)
this->elements[i] = previous[i];
for (int i = position; i <= this->length - 1; i++)
this->elements[i] = previous[i + 1];
delete[] previous;
}
/**
* Shrinks the size of the list, keeping only the elements that fit into the new size.
* The new size must be less than the current length of the list, or the function will exit.
*
* @param newSize New length of the list.
*
* @return (void).
**/
void shrink(const int& newSize) {
if (newSize >= this->length) {
std::cout << "error: (newSize) must be less than the current length of the list!" << std::endl;
exit(1);
}
size_t len = this->length - newSize;
for (int i = 0; i < len; i++)
this->erase(this->length - 1);
}
/**
* Swaps two elements at their given indexes.
*
* @param indexOne First index to swap.
* @param indexTwo Second index to swap.
*
* @return (void).
**/
void swap(const int& indexOne, const int& indexTwo) {
T temp = this->elements[indexOne];
this->elements[indexOne] = this->elements[indexTwo];
this->elements[indexTwo] = temp;
}
/**
* Performs an in-place bubble sort on the current list.
*
* @return (void).
**/
void sort(void) {
for (int i = 0; i < this->length; i++)
for (int j = 0; j < this->length - i - 1; j++)
if (this->elements[j] > this->elements[j + 1])
this->swap(j, j + 1); // Swap using index, not value.
}
/**
* Clears the list of all elements and resetting the length to zero.
*
* @return (void).
**/
void clear(void) {
this->elements = nullptr;
this->length = 0;
}
/**
* Prints the list to the console, all on one line.
*
* @return (void).
**/
void print(void) const {
for (int i = 0; i < this->length; i++)
std::cout << this->elements[i] << " ";
std::cout << std::endl;
}
/**
* Overload operator[] for list.
**/
T& operator[](const int& position) const {
this->checkRangeError(position);
return this->elements[position];
}
/**
* Overload operator== for list.
**/
bool operator==(list& rhs) const {
if (this->size() != rhs.size()) return false;
for (int i = 0; i < this->length; i++)
if (this->elements[i] != rhs[i]) return false;
return true;
}
};
And here's how I'm compiling:
run.sh
g++ program.cpp -std=c++2a -o program
./program
rm program
std::list
anymore, but rather ofstd::vector
. By the way, what exactly do you mean with "smaller version"? Do you want to reduce the code size, or the size of the memory used by yourlist
? \$\endgroup\$