Вы не должны вызывать деструкторы вручную. Они вызываются автоматически для вас.
Вам нужно использовать delete
(который также вызывает деструктор) и только на объектах, которые вы фактически создали с вызовом new
. Каждый другой объект будет уничтожен автоматически, когда будет достигнут конец его области видимости, и его деструктор будет вызван автоматически. Это также верно для членов классов.
Единственное исключение здесь, если вы использовали place-new для создания объекта или если вы намереваетесь повторно использовать его хранилище. Но вы, вероятно, не собираетесь делать что-то подобное.
Полностью удалите деструктор Dynamic_Graph
. Это не нужно.
Ваш класс doubly_linked_list
нарушает правило 0/3/5 . Правило гласит, что если вы определяете пользовательский деструктор, то вам также следует определить пользовательский конструктор копирования (/ перемещения) и оператор копирования (/ перемещения).
Если вы нарушаете это правило и вам случается сделать неявная или явная копия объекта этого класса, тогда вы, вероятно, будете иметь неопределенное поведение, потому что деструкторы будут вызываться дважды и пытаться удалить память дважды.
После редактирования вопроса с полным примером :
В коде, который вы сейчас показываете, деструктор для Doubly_Linked_List
вызывается четыре раза (см. https://godbolt.org/z/KmStwy). Эти вызовы вызваны тем, что Get_In_Nodes
и Get_Out_Nodes
возвращают Doubly_Linked_List
списки по значению как копии членов класса Graph_Node
. Поскольку вы вызываете эти функции четыре раза в main
, есть четыре Doubly_Linked_List
временных объекта, которые необходимо уничтожить (что компилятор делает автоматически).
Вы неправильно реализовали Doubly_Linked_List(const Doubly_Linked_List& list)
(и оператор назначения копирования) для , фактически скопировали весь список , поэтому ваша программа по-прежнему имеет неопределенное поведение. Вам необходимо реализовать операции копирования таким образом, чтобы весь список подвергался глубокому копированию, в противном случае вызов деструктора как оригинала, так и копии будет delete
одинаковыми узлами.
В качестве альтернативы вы можете определить операции копирования как удаленные:
Doubly_Linked_List(const Doubly_Linked_List& list) : head(list.head), tail(list.tail) = delete
Doubly_Linked_List& operator=(const Doubly_Linked_List& list) = delete;
, в этом случае компилятор не разрешит копирование и выдаст ошибку времени компиляции, если вы попытаетесь скопировать. Но ваша текущая реализация так же сломана, как и раньше. Вы просто скопировали то, что делают неявные операции копирования. Прочитайте ссылку о правиле 0/3/5 еще раз и внимательно, поскольку крайне важно избегать неопределенного поведения.
Тот факт, что деструктор вызывается несколько раз, сам по себе не является проблемой. Это нормально, если задействованы копии. Проблема только в том, что ваши операции копирования класса не работают. Если вы не хотите создавать копии в Get_In_Nodes
и Get_Out_Nodes
, тогда вместо этого возвращайте по ссылке.
Как правило, вы не должны использовать new
/ delete
в то, что вы делаете в современном C ++. Вместо этого вы можете использовать std::make_unique
и std::unique_ptr
для владения указателями, и если вы это сделаете, то ни одному из ваших показанных классов не понадобятся пользовательские деструкторы (по крайней мере, не пользовательские деструкторы, которые имеют эффективное поведение, отличное от неявного), и вы всегда можете используйте правило 0, означающее, что вам также не нужно реализовывать какие-либо операции копирования.
И если это не учебное упражнение, вы не должны сначала писать свой собственный список , std::list
отлично работает и почти наверняка превосходит то, что вы придумали.