Kod jest w miare ok, ale wydaje mi się, że w dziwny sposób podchodzisz do zadania :P. Nie rozumiem czemu destruktor miałby być szkieletem rozwiązania :D. Wg mnie lepiej byłoby najpierw naśmiecić, a jak już zobaczysz gdzie i jak zostalo naśmiecone to potem te śmieci zbierać. Nie na odwrót :D
Drobne poprawki, gdybym miał się bardzo czepiać:
Struct i class różnią się od siebie tylko domyślnym modyfikatorem dostępu i domyślnym typem dziedziczenia, ale w środowisku programistycznym utarło się, że struct jest wykorzystywany tam gdzie chcemy mieć taki pojemnik na dane bez żadnych metod. class List, struct Node.
List::List() {
head = NULL;
tail = NULL;
counter = 0;
}
coś takiego nie jest warte definiowania konstruktora skoro o wiele czytelniej od C++11 można napisać tak:
class List {
private:
Node * head = nullptr;
Node* tail = nullptr;
int counter = 0;
};
Node(int _data, Node *_next = NULL) {
data = _data;
next = _next;
}
W takim przypadku banalnego konstruktora czytelniej jest użyć listy inicjalizacyjnej i oczywiście definicje rzucić do pliku .cpp
List::Node::Node(int _data, Node *_next = NULL) : data(_data), next(_next) {}
Lista inicjalizacyjna implikuje proste przypisanie parametrów do składowych. Gdy widzisz kod w ciele konsturktora spodziewasz się logiki.
Generalnie nie powinno się zaczynać nazw identyfikatorów od podkreślenia, żeby uniknać kolizji z kompilatorem/bibliotekami. W przypadku inicjalizacji składowych parametrami o tych samych nazwach możesz do składowych dodawać jakiś prefix lub sufix. Osoboście spotkałem się z m_skladowa lub skladowa_. Wybierz jedną i trzymaj się tej konwencji.