【问题标题】:Debugging "malloc error: pointer being freed was not allocated", using gdb使用 gdb 调试“malloc 错误:未分配被释放的指针”
【发布时间】:2014-08-29 01:48:15
【问题描述】:

我正在尝试编写标准容器 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;

我发现问题出在删除数据上,但据我了解,数据总是用 new 初始化,所以我看不到问题所在。任何建议,即使是在代码的其他方面,都值得赞赏。

【问题讨论】:

  • delete NULL 是无操作 BTW,请使用 nullptr。此外,您没有调试最新的源代码。最后,节点的析构函数也不应该释放其兄弟节点。当它们破坏时会发生什么?
  • I am trying to write an minimalist version of the standard container std::list, as a C++ exercise 这就像一个初学钢琴的学生说“我正在尝试演奏贝多芬钢琴协奏曲的极简版本”。

标签: c++ debugging pointers memory-management gdb


【解决方案1】:

问题就在这里:

            ~Node() {
                if (data != NULL)
                    delete data;
                if (prev != NULL)
                    delete prev;
                if (next != NULL)
                    delete next;
            }

当你删除第一个节点时,它会尝试通过delete next;删除第二个节点

但是,在第二个节点的~Node() 中,它尝试通过delete prev;再次删除第一个节点。

正确的做法是只删除~Node()中的data;遍历列表以删除每个节点,而不是通过prev 和next 删除。

【讨论】:

  • 好的,这很有道理,但是你建议如何修改 ~iterator 方法,这样我就不会在不同的位置出现完全相同的错误?
  • 我建议永远不要在iterator() 和~iterator() 中分配或取消分配Node。让List的成员函数来做吧。
  • 如果是这样,那么删除迭代器的真正含义是什么,就像我在 push_back 中所做的那样?我认为迭代器应该删除节点,因为它携带指向节点的指针?
  • 另外,我不能以同样的方式使用代码,只是让一个节点在它的下一个或上一个节点中修改它对自身的引用,然后再删除它们?因此,如果您有 NULLab,对于删除 a,将其设为 NULLb,a 仍保持其指针,然后再删除 next 和 prev?这样他们就不会尝试再次删除?
  • @SamadwaraReddy 有了这样的实现,你怎么能删除列表中的单个元素?你只能破坏整个列表。
猜你喜欢
  • 2015-10-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-12
相关资源
最近更新 更多