Отладка «ошибка malloc: освобожденный указатель не был выделен», используя gdb

0

Я пытаюсь написать минималистскую версию стандартного контейнера 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;

Я вижу, что проблема заключается в удалении данных, но для моего понимания данные всегда инициализируются новыми, поэтому я не вижу проблемы. Любые предложения, даже по другим аспектам кода, приветствуются.

  • 0
    delete NULL - это запретная операция, и используйте nullptr . Кроме того, вы не отлаживаете свой последний источник. Наконец, деструктор для узла также не должен освобождать узлы-узлы. Что происходит, когда они разрушают?
  • 0
    I am trying to write an minimalist version of the standard container std::list, as a C++ exercise Это похоже на начинающего студента фортепиано, говорящего: «Я пытаюсь сыграть эту минималистскую версию фортепианного концерта Бетховена».
Теги:
pointers
debugging
gdb
memory-management

1 ответ

2
Лучший ответ

Проблема здесь:

            ~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.

  • 0
    Хорошо, это имеет смысл, но как бы вы предложили изменить метод ~ итератор, чтобы я не заканчивал тем же самым ошибкой в другом месте?
  • 0
    Я бы посоветовал никогда не размещать и не освобождать Node в iterator() и ~iterator() . Пусть функции-члены List делают это.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню