链表包含一个类抛出异常0xC0000005



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

#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;
}
};

这里是main函数和我要存储的类;

#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.我认为我缺乏使用指针的经验可能导致了问题,但如果你看到一些我不能,请启发我。

您发布的代码还有其他问题(例如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;
}

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

所以你不想返回对像result这样的堆栈分配变量的引用;您希望返回对节点本身(由insert()在堆上分配)中的数据的引用,因为在函数返回后,它仍然是一个有效的引用:

return search(indx)->data;

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

您需要为Vectem添加适当的构造函数(以及析构函数,复制构造函数和复制赋值操作符,根据规则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及以后的版本中,可以直接在成员的声明中初始化成员(同时,请确保根据规则5添加move构造函数和move赋值操作符),例如:

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()也有bug,因为它在检查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;
}

最新更新