Prosiłbym o ocenę jakości kodu i ewentualne wytknięcie błędów, wycieków pamięci, UB, możliwych optymalizacji. =)
template <class T>
class List {
private:
int length;
int capacity;
int log;
T *buffer;
void reserve(int capacity) {
T *newBuffer = new T[capacity];
memcpy(newBuffer, buffer, length*sizeof(T));
delete[] buffer;
buffer = newBuffer;
this->capacity = capacity;
}
public:
List() {
length = capacity = log = 0;
buffer = nullptr;
}
List(const List<T> &list) {
length = list.length;
log = list.log;
capacity = list.capacity;
buffer = new T[capacity];
memcpy(buffer, list.buffer, length*sizeof(T));
}
List(int capacity) {
log = (int)(Math::ceil(Math::log2(capacity))+0.5)+1; //W ten sposób w najgorszym przypadku, czyli np. log2(4) = 2.001, zostanie zarezerwowane 2 razy więcej pamięci niż to potrzebne. (int)(ceil()+0.5) nie pozwala ceil() na zwrócenie wartości mniejszej niż oczekiwana, czyli gdy ceil(1.5) = 1.999, jest to zamieniane na 2.
this->capacity = 0b1 << (log-1);
buffer = new T[this->capacity];
length = 0;
}
inline T &operator[](int index) {
return buffer[index];
}
T *begin() { return buffer; }
T *end() { return buffer + length; }
T &front() { return buffer[0]; }
T &back() { return buffer[length - 1]; }
int size() {
return length;
}
bool empty() {
return length == 0;
}
void clear() {
length = capacity = log = 0;
delete[] buffer;
buffer = nullptr;
}
int find(const T &element) {
for(int i=0; i<length; i++) {
if(buffer[i] == element)return i;
}
return -1;
}
void add(const T &element) {
if(length == capacity)reserve(0b1 << log++);
buffer[length++] = element;
}
void remove(int index) {
if(index < 0)return; //Tutaj UB jest jak najbardziej wskazane - jak programista użyje, tak dostanie. Sprawdzanie czy liczba jest ujemna ma jedynie umożliwić użycie List::remove(List::find(const T &))
T *i = &buffer[index];
memcpy(i, i+1, (--length-index)*sizeof(T));
delete i;
}
~List() {
delete[] buffer;
}
};
Rafbeamdelete
ma ponoć zabezpieczenie anulujące usuwanienullptr
?