C ++链表内存管理

时间:2009-10-15 05:06:47

标签: c++ memory-management

我试图在C ++中创建自己的基本单链表作为学习练习,而且我在内存管理部门遇到了一些困难。目前我有......

'Node'类:

class Node
{
public:
    char *value;
    Node *next;
    Node();
    ~Node();
};

Node::Node()
{
}

Node::~Node()
{
    delete[] value;
}

然后我的列表(为了简洁,我省略了某些方法调用):

class LinkedList
{
private:

    Node *head;

public:

    LinkedList();
    ~LinkedList();
    void Add(char **x);

};

LinkedList::LinkedList()
{
    head = 0;
}

LinkedList::~LinkedList()
{
    Node *temp;
    Node *current = head;

    while(current)
    {
        temp = current;
        current = current->next;
        delete temp;
    }
}

void LinkedList::Add(char **x)
{
    Node *nodeToAdd = new Node();
    nodeToAdd->value = *x;
    nodeToAdd->next = NULL;

    Node *current = head;

    if(!head)
    {
        head = nodeToAdd;
        return;
    }

    while(current->next)
    {
        current = current->next;
    }

    current->next = nodeToAdd;
}

我正在尝试按如下方式使用此代码(为了简洁起见,我省略了一些内容):

int main()
{
    LinkedList *list = new LinkedList();

    char *alpha = "alpha";
    char *beta = "beta";
    char *charlie = "charlie";
    char *delta = "delta";
    char *echo = "echo";

    list->Add(&alpha);
    list->Add(&beta);
    list->Add(&charlie);
    list->Add(&delta);
    list->Add(&echo);

    delete list;

}

主要删除列表的最后一次调用会产生错误:

Debug Assertion Failed! Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

我在这里做错了什么?

6 个答案:

答案 0 :(得分:7)

各种Node::value指向的数据不会动态分配,因此您不应删除它们。应用“所有权”的概念,节点应该创建自己的数据副本,他们拥有并可以删除,或者节点不拥有数据,因此他们不应该负责删除它。

您还可以使用引用计数实现多个所有权,例如Objective-C(请参阅Objective-C Memory Management Rules以获取更多信息),但您必须小心避免所有权周期。您经常在第三方智能指针中找到某种类型的引用计数,例如Boost's smart_ptr library。由于您是为了学习体验而这样做,因此使用库比使用库更有意义。当然,你现在也可以使用一个库,让你专注于你想要学习的东西。

  有一天,一个学生来到Moon并说:“我理解如何制作一个更好的垃圾收集器。我们必须保留每个缺点指针的引用计数。“

     月亮耐心地告诉学生以下的故事:

     

“有一天,一个学生来到Moon说:'我明白如何制作一个更好的垃圾收集器......

答案 1 :(得分:2)

您正在尝试释放未在堆上分配的内存。

char *alpha = "alpha"; --- not allocated on heap

delete[]析构函数中调用Node会导致堆损坏。

有些观点:

1)在构造函数中正确初始化指针:

Node::Node():value(NULL),next(NULL)
{
}

2)拥有价值所有权。

  • 在堆上分配内存并复制 内容

答案 2 :(得分:1)

如果它不是由new运算符创建的,则不应释放指针使用delete [] / delete。 delete []操作有一些操作,例如从托管池中释放/回收标记的内存。由于您的指针不属于这些东西,因此会出现问题。恕我直言,底层的delete []代码是_BLOCK_TYPE_IS_VALID(pHead-> nBlockUse)的东西。

答案 3 :(得分:0)

问题是你假设你可以删除节点内的数据,但是你传递了指向字符串文字的指针,而你无法删除。

如果您假设Node对象控制其中数据的生命周期,则Node构造函数或LinkedList中的Add函数必须复制正在传递的数据。

答案 4 :(得分:0)

在析构函数中,您尝试对删除(删除[])静态字符串进行数组删除。您已更改添加功能以保留字符串并首先将其复制。请参阅下面的代码。

但是,如果我是你并且对内存管理还不熟悉,我真的会使用类似CString而不是原始的“char *”,因为它更容易处理。

void LinkedList::Add(const char *x)
{
    Node *nodeToAdd = new Node();

    int len=strlen(x);
    nodeToAdd->value = new char [len+1];    // room for string + terminating 0
    strcpy(nodeToAdd->value,x);

    nodeToAdd->next = NULL;

    Node *current = head;

    if(!head)
    {
        head = nodeToAdd;
        return;
    }

    while(current->next)
    {
        current = current->next;
    }

    current->next = nodeToAdd;
}

答案 5 :(得分:-1)

Node类中的

值和下一个没有分配内存。你应该在Node的构造函数中分配内存。