Я пытаюсь написать минималистскую версию стандартного контейнера std :: list, как упражнение C++. Тем не менее, я сталкиваюсь с трудностями с управлением памятью, поскольку я новичок в C++ и исхожу из python/java, где нам не о чем беспокоиться. Код ниже:
#include <memory>
#include <cstddef>
#include <iostream>
template <typename T> class List {
public:
typedef std::size_t size_type;
typedef T value_type;
typedef T& reference;
typedef const T& const_reference;
template <typename U> class Node {
public:
Node() {
data = NULL;
init();
}
Node(const U val) {
data = new U(val);
init();
}
void init() {
prev = NULL;
next = NULL;
}
~Node() {
if (data != NULL)
delete data;
if (prev != NULL)
delete prev;
if (next != NULL)
delete next;
}
U* data;
Node* prev;
Node* next;
};
class iterator {
public:
iterator() {
n = new Node<T>();
}
iterator(const T val) {
n = new Node<T>(val);
}
iterator(Node<T>* nodeptr) {
n = nodeptr;
}
~iterator() {
delete n;
}
iterator operator++() {
n = n->next;
}
iterator operator--() {
n = n->prev;
}
T& operator*() {
return *(n->data);
}
bool operator==(iterator other) {
return (this->n == other.n);
}
Node<T>* n;
};
List() {
_begin = new iterator();
_end = new iterator(begin.n);
}
List(size_type n, T val) {
init(val);
}
~List() {
delete _begin;
delete _end;
}
void init(T val) {
_begin = new iterator(val);
Node<T>* nextNode = new Node<T>();
_begin->n->next = nextNode;
nextNode->prev = _begin->n;
_end = new iterator(nextNode);
}
void push_back(T val) {
if(_begin == _end) {
delete _begin;
delete _end;
init(val);
}
else {
Node<T>* endNode = _end->n;
Node<T>* lastNode = endNode->prev;
Node<T>* append = new Node<T>(val);
lastNode->next = append;
append->next = endNode;
append->prev = lastNode;
endNode->prev = append;
}
}
iterator begin() {return *_begin;}
iterator end() {return *_end;}
private:
iterator* _begin;
iterator* _end;
};
int main() {
List<int> derp= List<int>(3,3);
List<int>::iterator i = derp.begin();
std::cout << *i;
derp.push_back(4);
std::cout << *i;
}
Когда я запускаю код, я получаю следующий вывод:
a.out(814) malloc: *** error for object 0x7fbab0403a70: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
33Abort trap: 6
Я использовал отладчик GNU для установки точки прерывания по назначению и получил следующие результаты:
(gdb) break malloc_error_break
Function "malloc_error_break" not defined.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (malloc_error_break) pending.
(gdb) run
Starting program: /Users/samadwara/Projects/C++/a.out
Reading symbols for shared libraries ++.............................. done
Breakpoint 1 at 0x7fff90721588
Pending breakpoint 1 - "malloc_error_break" resolved
a.out(835) malloc: *** error for object 0x100103a90: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Breakpoint 1, 0x00007fff90721588 in malloc_error_break ()
(gdb) backtrace
#0 0x00007fff90721588 in malloc_error_break ()
#1 0x00007fff90722942 in free ()
#2 0x0000000100001864 in List<int>::Node<int>::~Node (this=0x100103a70) at list2.cpp:30
#3 0x0000000100001894 in List<int>::Node<int>::~Node (this=0x100103ad0) at list2.cpp:32
#4 0x00000001000018d0 in List<int>::Node<int>::~Node (this=0x100103a70) at list2.cpp:34
#5 0x000000010000190f in List<int>::iterator::~iterator (this=0x7fff5fbff930) at list2.cpp:55
#6 0x00000001000012ae in main () at list2.cpp:117
(gdb) frame 2
#2 0x0000000100001864 in List<int>::Node<int>::~Node (this=0x100103a70) at list2.cpp:30
warning: Source file is more recent than executable.
30 delete data;
(gdb) l
25 next = NULL;
26 }
27
28 ~Node() {
29 if (data != NULL)
30 delete data;
31 if (prev != NULL)
32 delete prev;
33 if (next != NULL)
34 delete next;
Я вижу, что проблема заключается в удалении данных, но для моего понимания данные всегда инициализируются новыми, поэтому я не вижу проблемы. Любые предложения, даже по другим аспектам кода, приветствуются.
Проблема здесь:
~Node() {
if (data != NULL)
delete data;
if (prev != NULL)
delete prev;
if (next != NULL)
delete next;
}
Когда вы удаляете 1-й узел, он пытается удалить второй узел путем delete next;
Однако в ~Node()
для второго узла он пытается удалить 1-й узел снова с помощью delete prev;
,
Правильный способ - удалить только data
в ~Node()
; итерации по списку, чтобы удалить каждый узел вместо удаления из prev
и next
.
Node
в iterator()
и ~iterator()
. Пусть функции-члены List
делают это.
delete NULL
- это запретная операция, и используйтеnullptr
. Кроме того, вы не отлаживаете свой последний источник. Наконец, деструктор для узла также не должен освобождать узлы-узлы. Что происходит, когда они разрушают?I am trying to write an minimalist version of the standard container std::list, as a C++ exercise
Это похоже на начинающего студента фортепиано, говорящего: «Я пытаюсь сыграть эту минималистскую версию фортепианного концерта Бетховена».