这是针对学校项目的。我有一个叫做buddy的类和一个链接列表buddyList。在调试时,我遇到了一些我认为已正确解决的nullptr异常,但最后我尝试调试时,遇到了此异常。我该怎么做才能解决此问题? 请记住,其中一些代码是通过讲师提供的,并且该项目的目标是向现有的类中添加特定的方法。谢谢!
// buddy.h
private void button1_Click(object sender, EventArgs e)
{
Regex regex1 = new Regex("^[a-zA-Z ]+$");
Regex dat = new Regex("^(0[1-9]|[12][0-9]|3[01])(0[1-9]|1[012])([0-9]{2})[-]([0-9]{5})$");
Regex epasts = new Regex(@"^([\w\.\-]+)@([\w\-]+)((\.(\w){2,3})+)$");
// Use a boolean to determine whether there is an error
var valid = true;
if (!regex1.IsMatch(textBox1.Text))
{
valid = false;
label5.ForeColor = Color.Red;
label5.Text = "Incorrectly entered name!";
}
else
{
label5.Text = "";
}
if (String.IsNullOrEmpty(textBox1.Text))
{
valid = false;
label5.ForeColor = Color.Red;
label5.Text = "Name wasn't entered!";
}
if (!regex1.IsMatch(textBox2.Text))
{
valid = false;
label6.ForeColor = Color.Red;
label6.Text = "Surname entered incorrectly!";
}
else
{
label6.Text = "";
}
if (String.IsNullOrEmpty(textBox2.Text))
{
valid = false;
label6.ForeColor = Color.Red;
label6.Text = "No surname!";
}
if (!dat.IsMatch(textBox3.Text))
{
valid = false;
label7.ForeColor = Color.Red;
label7.Text = "Incorrect code!";
}
else
{
label7.Text = "";
}
if (String.IsNullOrEmpty(textBox3.Text))
{
valid = false;
label7.ForeColor = Color.Red;
label7.Text = "Not entered!";
}
if (!epasts.IsMatch(textBox4.Text))
{
valid = false;
label8.ForeColor = Color.Red;
label8.Text = "Incorrectly entered email!";
}
else
{
label8.Text = "";
}
if (String.IsNullOrEmpty(textBox4.Text))
{
valid = false;
label8.ForeColor = Color.Red;
label8.Text = "Email not entered!";
}
// Now you can check if there is an error
if (valid)
{
// This doesn't make any sense - because the user can ONLY click ok
//if (MessageBox.Show("Data is being saved", "Data saving", MessageBoxButtons.OK) == DialogResult.OK)
// I think you maybe meant something like this?
if (MessageBox.Show("Data is being saved", "Data saving", MessageBoxButtons.OKCancel) == DialogResult.OK)
{
// And here - I'm assuming you would save the data somewhere and then clear the textboxes?
textBox1.Text = "";
textBox2.Text = "";
textBox3.Text = "";
textBox4.Text = "";
}
}
else
{
MessageBox.Show("Please correct the errors and try again");
}
}
// buddyList.h
#pragma once
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
class buddy {
friend class buddyList;
public:
buddy() {
first = last = phone = ""; next = NULL;
cout << "Buddy allocated\n";
}
~buddy() {
if (next != NULL) {
delete next;
cout << "Buddy " << first << " " << last << " deallocated!\n";
}
}
void set(string fname, string lname, string tele) {
first = fname;
last = lname;
phone = tele;
}
void print() {
cout << left << setw(15) << last << setw(15) << first << " " << phone << endl;
}
private:
string first;
string last;
string phone;
buddy * next;
};
// buddyList.cpp
#pragma once
#include <string>
#include "buddy.h"
using namespace std;
class buddyList {
public:
buddyList();
~buddyList();
void add(string fname, string lname, string phone);
void print();
int drop(string fname, string lname);
void sort();
void read();
private:
buddy * head;
buddy* search(string fname, string lname);
buddy* maxByName();
void remove(buddy * r);
void add(buddy * n);
};
}
答案 0 :(得分:2)
堆栈溢出通常是由递归疯狂引起的。通过这种方式,我的意思是您正在执行某种递归操作,例如delete
-在当前元素的析构函数中对下一个(列表中的)元素进行操作,但是由于某些原因,列表的完整性受到损害。 / p>
由于您的buddy
类仅包含有关列表中元素的信息,因此您可能应该查看列表代码本身。这在行中非常诱人:
friend class buddyList;
对于析构函数而言,首先清除其“拥有”的所有项(例如列表的其余部分)没有任何问题,但您必须正确地进行操作。从您提供的代码来看,看起来还可以,但是一切都基于buddyList
正常工作的事实。
事实上,现在您已经添加了一些buddyList
代码,这似乎是确切的问题。查看添加项目的代码:
buddy * b = new buddy;
b->first = fname;
b->last = lname;
b->phone = phone;
add(b);
delete b; // Hmm!!
您在这里遇到了严重的问题。您分配了一个新的伙伴,将指向它的指针添加到列表中,然后释放它所引用的内存。例如,如果内存被其他地方重用(例如列表中的另一个节点)而仍被列表引用,那将不会很好地结束。
所以,这就是我的建议。
正确区分职责。给定的节点永远不必与列表中的其他节点相关。列表本身应该负责清理自己。
请勿使用递归进行清理。递归的理想用例是快速减少问题空间。例如,在二进制搜索中,您在每个递归级别上都删除了剩余问题空间的一半。拥有一百万个节点的列表,每级删除一个节点,几乎可以肯定的是,您的堆栈会溢出一百万个单独的帧。
如果您不使用C ++智能指针(a),请学习如何遵循所有权流程,不要将一个对象“交给”其他对象,然后立即执行它不可用:-)
例如,这是一个实现,在仍然使用原始指针的情况下,解决了上面的前两点:
#include <iostream>
#include <memory>
class Node {
public:
Node(const std::string &str): m_str(str), m_next(nullptr) {}
private:
friend class NodeList;
std::string m_str;
Node *m_next;
};
class NodeList {
public:
NodeList(): m_head(nullptr), m_tail(nullptr) {};
~NodeList() { clear(); }
void print() {
Node *node = m_head;
std::cout << "List:";
while (node != nullptr) {
std::cout << " " << node->m_str;
node = node->m_next;
}
std::cout << "\n";
}
void add(const std::string &str) {
auto newNode = new Node(str);
if (m_head == nullptr) {
m_head = m_tail = newNode;
} else {
m_tail->m_next = newNode;
m_tail = newNode;
}
}
// List is responsible for cleaning itself up, and
// it does it iteratively to mimimise chance of
// stack blowout.
void clear() {
while (m_head != nullptr) {
Node *save = m_head->m_next;
delete m_head;
m_head = save;
}
m_tail = nullptr;
}
private:
Node *m_head, *m_tail;
};
int main() {
NodeList list;
list.print();
list.add("paxdiablo"); list.add("george"); list.add("bob");
list.print();
list.clear();
list.print();
}
按预期,输出为:
List:
List: paxdiablo george bob
List:
(a)如今在非常的少数情况下,您应该使用new
或delete
关键字。如果您完全理解并控制对象的所有权,就可以了,但是,如果有任何疑问,现代C ++会提供智能指针来简化对象的管理。