为啥我的类节点会覆盖自己而不是创建新的节点对象

Posted

技术标签:

【中文标题】为啥我的类节点会覆盖自己而不是创建新的节点对象【英文标题】:Why is my class node overwriting itself instead of making a new node object为什么我的类节点会覆盖自己而不是创建新的节点对象 【发布时间】:2020-02-03 07:21:09 【问题描述】:

有人可以运行这段代码并告诉我为什么插入中的节点不断被覆盖吗?

#ifndef LinkedList_hpp
#define LinkedList_hpp

#include <stdio.h>
#include <utility>

template<class T>class LinkedList
public:
LinkedList()
        head = nullptr;
        tail = nullptr;
        size = 0;
    
    //void insert(T val);
    class Node
        public:
        Node* next;
        T* value;
        Node* prev;
        Node(T* value)
            this->value = value;
        
        Node()
        
        Node(T* value,Node* prev, Node* next)
            this->value = value;
            this->next = next;
            this->prev = prev;
        
        Node* operator=(const Node& node)
            this->value = node.value;
            this->prev = node.prev;
            this->next = node.next;
            return *this;
        

    ;
public:
    Node* head;
    Node* tail;
    int size;
    void insert(T val)

在这一行,如果前一个 head 是 10,则当前 val 40 会覆盖旧的 head 值并插入一个 val 40 的新节点

        Node* temp = new Node(&val);
        if(head==nullptr)
            head = temp;
            tail = temp;
        else
            temp->next = head;
            head->prev = temp;
            head = temp;
        
        size++;
    
#endif

#include <iostream>
#include "LinkedList.hpp"

int main(int argc, const char * argv[]) 

   // LinkedList<int> t;
    int h = 7;
    int j = 10;
    int k = 40;
    LinkedList<int>* list1 = new LinkedList<int>();


    list1->insert(h);
    list1->insert(j);
    list1->insert(k);

return 0;

每次调用insert并构造一个新节点时,它都会覆盖旧值,一切都变成当前的Val

【问题讨论】:

【参考方案1】:
void insert(T val)

val 是这个函数的一个参数。这个对象,这个val,只存在于这个函数返回之前。此时它会被销毁,就像在函数内的非静态范围内声明的所有其他内容一样。这就是 C++ 的工作原理。一旦insert() 返回,这个val 就没有了。它不复存在。它去见它的制造者。它变成了一个前对象,不再存在,完全是过去了。

您的 insert() 函数执行以下操作:

Node* temp = new Node(&val);

您将指向此val 参数的指针传递给Node 的构造函数,然后Node 将指向insert() 的参数的指针保存为它自己的类成员。

这很好,但是一旦insert() 返回,new-ed Node 中保存的指针就变成了一个指向已销毁对象的指针,取消引用这个指针就变成了未定义的行为。

然后,您稍后会尝试取消引用原始指针,该指针不再指向有效对象。

这解释了您的代码中观察到的未定义行为。

底线是您的类和模板的设计存在根本缺陷。 Node 使用指针没有明显的目的。 Node 应该简单地将T 存储为它自己的类成员,作为value,而不是value 是指向存在于某处的其他T 的指针,并且可以随时被销毁,这不是在Node 的控制下。

所示代码中的另一个问题是Node 的两个构造函数未能将nextprev 指针初始化为NULL。这也会导致未定义的行为。

【讨论】:

谢谢!我通过不使 val 成为指针来解决此问题。你解释它的方式很有意义。我的印象是该对象指向保持范围,但我猜不是。泰!【参考方案2】:
void insert(T val)

按值获取参数,因此val 是本地副本而不是原始副本。

Node* temp = new Node(&val);

存储指向此本地副本的指针。副本超出范围,因此您在插入退出后看到的是内存中存在的不再有效的幽灵。在这种情况下,幽灵似乎总是持有最后一个值集。

解决方案:

聪明的方式:直接存储Node::value,而不是作为你需要与节点一起保持活动的指针。这种方式的内存管理要少得多。

T* value;

变成

T value;

Node(T* value)
    this->value = value;

变成

Node(T value)
        this->value = value;

value 的其他用途必须相应更新。总的来说,new 让it should be used sparingly 很头疼。

愚蠢的方式:通过引用传递

void insert(T &val)

使指针指向寿命更长的原件。

【讨论】:

以上是关于为啥我的类节点会覆盖自己而不是创建新的节点对象的主要内容,如果未能解决你的问题,请参考以下文章

如何防止键盘覆盖我的 UI 而不是调整它的大小?

为啥我的对象会在 C++ 中被覆盖?

为啥LinkedList中的类节点定义为静态而不是普通类[重复]

覆盖另一个程序集中的内部抽象方法

为啥我的 for 循环覆盖而不是追加?

django网页系统,为啥我跳转网页时总会打开一个新的网页,而不是覆盖原来的网页?