【问题标题】:Linked list consist of a class throws exception 0xC0000005链表包含一个类抛出异常 0xC0000005
【发布时间】:2021-04-20 01:08:51
【问题描述】:

所以我有一个自己的链表实现,它可以成功地保留整数并在需要时使用重载的 [] 运算符调用它们,但是在我的链表中存储一个类时,我似乎无法调用适当的类(使用相同的 [] 运算符)。 被调用的函数和我的链接列表的成员;

#include <iostream>
#include <assert.h>

template<typename T>
struct node {
    T data;
    node<T>* next;
};

template<typename T>
class Vectem {
private:
    node<T>* head;
    node<T>* last;
    int lenght;
public:
    void insert(T value) {
        last->next = new node<T>;
        last = last->next;
        last->data = value;
        last->next = NULL;
        if (isEmpty()) {
            head = last;
        }
        lenght++;
    }
    node<T>* search(int indx) {
        node<T>* current;
        current = head;
        int count=0;
        while (current != NULL) {
            if (count == indx) {
                break;
            }
            current = current->next;
            count++;
        }
        return current;
    }
    T& operator [](int indx) {
        assert(indx >= lenght - 1);
        T result;
        result = search(indx)->data;
        return result;
    }
};

这是我尝试存储的主要功能和类;

#include <iostream>
#include <fstream>
#include <string>
#include "VectemLibrary.h"
class word {
public:
    std::string value;
    int count;
    word(std::string value, int count): value(value),count(count) {

    }
    word() {
        value = "NOT ASSIGNED";
        count = 0;
    }
    word(const word& w1) {
        value = w1.value;
        count = w1.count;
    }
    ~word() {
        std::cout << "Word Destroyed" << std::endl;
    }
};
int main()
{
    Vectem<word> wordContainer;
    word newWord("hello", 1);
    wordContainer.insert(newWord);
    std::cout << wordContainer[0].value;
    
}

Visual Studio 在最后一行给了我这个消息的期望,我用[] 调用链表的第一个成员; 在 Top 10 words.exe 中的 0x7A0CF3BE (ucrtbased.dll) 处引发异常:0xC0000005:访问冲突读取位置 0xCCCCCCCC。 我认为我缺乏指针经验可能会导致问题,但是如果您看到我看不到的东西,请赐教。

【问题讨论】:

  • T result; ...return result; 您正在返回对局部变量的引用。试试return search(indx)-&gt;data;
  • 另外,在insert() 中有last-&gt;next = new node&lt;T&gt;;。但是第一次调用这个函数时last 的值是多少?

标签: c++ class linked-list


【解决方案1】:

您发布的代码也存在其他问题(例如,isEmpty() 未声明或定义),但我将重点关注您明确提到的问题。

在您的运营商中:

T& operator [](int indx) {
    assert(indx >= lenght - 1);
    
    // You declare this variable on the stack
    T result;
    
    result = search(indx)->data;
    
    // And then you return this variable by reference; this is not okay
    return result;
}

正如我的代码 cmets 中提到的(以及 @Johnny Mopp 在他对您的帖子的评论中),您不应该(不能)返回指向在返回函数中声明并在堆栈上构造的变量的引用或指针.一旦函数调用结束,堆栈上的任何内容都将被销毁,因此任何返回的指针或对此类变量的引用都将是悬空引用;使用所述指针或引用将导致未定义的行为。

因此,您不想返回对堆栈分配变量的引用,例如 result;您想返回对节点本身内数据的引用(由insert() 在堆上分配),因为在函数返回后它仍然是有效的引用:

return search(indx)-&gt;data;

【讨论】:

  • 其他所有功能均已实现。我只是没有分享整个代码,以免浪费您的时间阅读它,因为它们工作得很好,并且返回 search(indx)->data 工作得很好。谢谢你和@Johnny Mopp。
【解决方案2】:

您的代码有几个问题,但最重要的是您根本没有初始化Vectemheadlastlenght 成员。地址0xCCCCCCCC 的访问冲突错误很好地表明正在访问未初始化的内存,因为某些编译器/设置用0xCC 字节填充未初始化的内存,因此headlast 在您的情况下最初是0xCCCCCCCC .

您需要向Vectem 添加适当的构造函数(以及析构函数、复制构造函数和复制赋值运算符,根据Rule of 3),例如:

template<typename T>
class Vectem {
private:
    node<T>* head;
    node<T>* last;
    int lenght;
public:
    Vectem() : head(NULL), last(NULL), lenght(0) {}

    Vectem(const Vectem &src) : head(NULL), last(NULL), lenght(0)
    {
        // copy src's data to *this as needed ...
    }

    ~Vectem()
    {
        // cleanup *this as needed ...
    }

    Vectem& operator=(const Vectem &rhs)
    {
        if (&rhs != this) {
            // clear *this, and copy rhs's data to *this, as needed ...
        }
        return *this;
    }

    ...
};

或者,在 C++11 及更高版本中,您可以直接在其声明中初始化成员(另外,请务必根据 Rule of 5 添加移动构造函数和移动赋值运算符),例如:

template<typename T>
class Vectem {
private:
    node<T>* head = nullptr;
    node<T>* last = nullptr;
    int lenght = 0;
public:
    Vectem() = default;

    Vectem(const Vectem &src)
    {
        // copy src's data to *this as needed ...
    }

    Vectem(Vectem &&src) : head(src.head), last(src.last), lenght(src.lenght) 
    {
        src.head = nullptr;
        src.last = nullptr;
        src.lenght = 0;
    }

    ~Vectem()
    {
        // cleanup *this as needed ...
    }

    Vectem& operator=(const Vectem &rhs)
    {
        if (&rhs != this) {
            // clear *this, and copy rhs's data to *this, as needed ...
        }
        return *this;
    }

    Vectem& operator=(Vectem &&rhs)
    {
        // clear *this as needed...

        head = rhs.head; rhs.head = nullptr;
        last = rhs.last; rhs.last = nullptr;
        lenght = rhs.lenght; rhs.lenght = 0;

       return *this;
    }

    ...
};

话虽如此,insert() 也是有问题的,因为它在检查 last 是否实际上指向有效节点之前取消引用 last。尝试更多类似的方法:

void insert(T value) {
    node<T> *n = new node<T>{value, NULL};
    if (!head) head = n;
    if (last) last->next = n;
    last = n;
    ++lenght;
}

或者:

void insert(T value) {
    node<T> **p = (last) ? &(last->next) : &head;
    *p = new node<T>{value, NULL};
    last = *p;
    ++lenght;
}

【讨论】:

  • 实际上我没有发布整个图书馆,以免浪费您的时间阅读所有内容。我坚持如果我只是展示正在使用的功能,这对每个人都会更好,但我想我错了。 Vectem 具有所有需要的构造函数并且工作正常,但你是对的,我也应该发布它们。感谢你付出的努力。看看你的实现对我很有用。
猜你喜欢
  • 2023-03-09
  • 2019-04-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多