Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/157.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何正确实现三大功能:单链表(C++)_C++_List_Memory Management_Linked List_Destructor - Fatal编程技术网

如何正确实现三大功能:单链表(C++)

如何正确实现三大功能:单链表(C++),c++,list,memory-management,linked-list,destructor,C++,List,Memory Management,Linked List,Destructor,我正在编写一个程序,其中包含一个单独链接的列表来保存购物列表。每个节点都有项目名称、数量和数量描述,即鸡蛋的打数。除了析构函数,程序中的所有东西都可以找到。但我似乎找不到它有什么问题 驱动程序将执行到代码返回0的结尾;,然后调用析构函数并在删除当前行上停止;我谨此致辞: 项目14.exe中0x0FC7A9E8 msvcr120d.dll处的未处理异常:0xC0000005:访问冲突读取位置0xFEEEFEE2 我已经发布了下面三大功能的实现。默认构造函数首先将指针初始化为null,最后将节点计数

我正在编写一个程序,其中包含一个单独链接的列表来保存购物列表。每个节点都有项目名称、数量和数量描述,即鸡蛋的打数。除了析构函数,程序中的所有东西都可以找到。但我似乎找不到它有什么问题

驱动程序将执行到代码返回0的结尾;,然后调用析构函数并在删除当前行上停止;我谨此致辞:

项目14.exe中0x0FC7A9E8 msvcr120d.dll处的未处理异常:0xC0000005:访问冲突读取位置0xFEEEFEE2

我已经发布了下面三大功能的实现。默认构造函数首先将指针初始化为null,最后将节点计数初始化为0

我似乎找不到问题所在。有什么帮助吗

List::List(const List& b)
{
    Node* newNodePtr = new Node;
    Node* nodeCopy = b.first;
    newNodePtr = nodeCopy;
    first = newNodePtr;
    last = newNodePtr;
    nodeCount++;
    nodeCopy = nodeCopy->getNext();
    while (last != b.last)
    {
        Node* newNode = new Node;
        newNode = nodeCopy;
        Node* currentNode = last;
        currentNode->setNext(newNode);
        last = newNode;
        nodeCount++;
        nodeCopy = nodeCopy->getNext();
    }
}

List::~List()
{
    Node* current = first;
    while (current != nullptr)
    {
        Node* _next = current->getNext();
        delete current;
        current = _next;
    }
    first = nullptr;
    last = nullptr;
}

List& List::operator=(const List& rho)
{
    Node* current = first;
    while (current != nullptr)
    {
        Node* _next = current->getNext();
        delete current;
        current = _next;
    }
    first = nullptr;
    last = nullptr;

    Node* newNodePtr = new Node;
    Node* nodeCopy = rho.first;
    newNodePtr = nodeCopy;
    first = newNodePtr;
    last = newNodePtr;
    nodeCount++;
    nodeCopy = nodeCopy->getNext();
    while (last != rho.last)
    {
        Node* newNode = new Node;
        newNode = nodeCopy;
        Node* currentNode = last;
        currentNode->setNext(newNode);
        last = newNode;
        nodeCount++;
        nodeCopy = nodeCopy->getNext();
    }
    return *this;
}
编辑:我还添加了我的push_-back函数,如下所示:

void List::push_back(Node* newNode)
{
if (first == nullptr)
{
    first = newNode;
    last = newNode;
}
else
{
    Node* currentNode = last;
    currentNode->setNext(newNode);
    last = newNode;
}
nodeCount++;
}
好吧,我想我明白了。这段代码似乎有效,它适合我的教授提供的驱动程序。下面我介绍了三大函数以及它们调用的所有其他函数:

List::List(const List& b)
{
    this->copyList(b);
}

List::~List()
{
    this->clearList();
}

List& List::operator=(const List& rho)
{
    this->clearList();
    this->copyList(rho);
    return *this;
}

void List::clearList()
{
    Node* current = first;
    while (current != nullptr)
    {
        current = pop_front();
        delete current;
        current = first;
    }
    first = nullptr;
    last = nullptr;
}

void List::copyList(const List& b)
{
    first = nullptr;
    last = nullptr;
    nodeCount = 0;
    Node *headNode = b.getFirst();
    while (headNode != nullptr)
    {
        string des = headNode->getDescription();
        string qNa = headNode->getQuantityName();
        int qNu = headNode->getQuantityNumber();
        Node* newNode = new Node(qNu, qNa, des);
        push_back(newNode);
        headNode = headNode->getNext();
    }
}

Node* List::pop_front()
{
    Node* saveFirst = first;
    first = first->getNext();
    nodeCount--;
    return saveFirst;
}

void List::push_back(Node* newNode)
{
    if (nodeCount == 0)
    {
        first = newNode;
        last = newNode;
    }
    else
    {
        Node* currentNode = last;
        currentNode->setNext(newNode);
        last = newNode;
    }
    nodeCount++;
}

它至少在一定程度上取决于调用析构函数时first指向什么

您的代码没有复制节点的内容。相反,它只是操纵指针,因此,正如dyp指出的那样,您存在以下漏洞: Node*newNodePtr=新节点; Node*nodeCopy=b.first; newNodePtr=nodeCopy

您可能需要仔细阅读复制交换习惯用法。

这可能无法解决您的确切问题,但如果您有您提到的函数,那么复制构造函数的伪代码将如下所示

List::List(const List& b)
{
   Node *headNode = b.getHeadNode();
   while (headNode != NULL)
   {
      push_back(headNode->getDataFromNode());
      headNode = headNode->getNextNode();
  }
}
基本上,这就是整个复制构造函数。您基本上是从列表中的第一个节点开始,从该节点获取数据,然后调用push_back来添加新数据。我假设push_back完成了创建节点、向其中添加数据以及将其正确放置在列表后面的所有棘手工作

注意这个实现是多么的小、紧凑和直观。我们知道,要创建链接列表的副本,我们需要做的就是首先确保列表是空的(对于新对象是空的),然后继续将旧列表中的项目添加到新列表中。由于push_back将一个项目添加到列表中,并且具有创建节点并将其链接到结束节点的所有复杂性,因此我们以一种智能的方式使用它来创建副本

请注意,您还需要一个赋值运算符来配合复制构造函数。本例中的赋值运算符只是调用clear,如果您有这样一个函数,可以在继续之前删除所有节点

请记住,所有这些都要求您的push_back功能能够完美地工作。它应该知道如何正确地处理在空列表和非空列表末尾的插入

编辑:

如果驱动程序代码在push_-back之前创建了新节点,因此push_-back不会分配新节点,则可以使用替代代码:

List::List(const List& b)
{
   Node *headNode = b.getHeadNode();
   while (headNode != NULL)
   {
      Node *newNode = new Node(headNode->getDataFromNode());
      push_back(newNode);
      headNode = headNode->getNextNode();
  }
}

在另一个版本中,我假设可以使用数据作为参数创建新节点的构造函数。我个人不喜欢让push_back不完成创建节点的所有工作的设计,但这是另一个问题。

节点的析构函数呢?你能给我们看一下吗?教授告诉我不要在Node类中包含析构函数。这段代码异常不安全,泄漏非常严重。您的教授是否也禁止您使用std::shared_ptr?泄漏的一个示例:Node*newNodePtr=newnode;Node*nodeCopy=b.first;newNodePtr=nodeCopy;泄漏通过new.@Arun分配的内存-完全正确,我同意。很多海报都有这些链表任务,并且实现了复制构造函数,这是很难做到的。他们没有看到他们正在编写的所有代码都已经在其他函数中完成了。如果他们没有编写这些其他函数,那么他们编写的链表有什么好处,例如,如果您无法从中获取任何信息或向其中添加项目。感谢您的帮助!如果你不介意的话,我把我的固定代码添加到了帖子里。我没有在push_-back函数中动态分配新节点的唯一原因是因为驱动程序已经这样做了,我们不应该更改提供的驱动程序。我通过在copyList函数中分配一个新节点来弥补这一点。但是,在这个项目之外,我知道你在说什么,我会确保在类代码中创建节点。@user3208991-我更新了我的答案,以包括你当前的场景,即“向后推”,只需将节点添加到列表的末尾。