为什么我的类节点会覆盖自身而不是创建新的节点对象

时间:2019-10-05 03:30:25

标签: c++ list templates overwrite

有人可以运行此代码,并告诉我为什么insert中的节点不断被覆盖吗?

#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

2 个答案:

答案 0 :(得分:2)

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的两个构造函数无法初始化next的{​​{1}}和prev指针。这也会导致不确定的行为。

答案 1 :(得分:1)

<form id="form">
    <input type="number" min="8" name="number" />
    <input type="submit" value="submit">
</form>

<script>

    var number = 0;
    var $form = $("#form");
    var $input = $form.find("input[name=number]");

    $form.submit(function(e){

        e.preventDefault();

        number = +($input.val()); 




    });

</script> 

按值接受参数,因此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令人头疼,it should be used sparingly

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

new

,以便指针指向寿命更长的原稿。