我试图在C ++中实现单一链接列表类。我已经重载了赋值运算符来克隆列表。克隆本身似乎工作正常,但程序在删除克隆列表时崩溃,这使我怀疑在复制过程中是否存在错误。
非常感谢任何帮助。 这是overloaded =运算符的代码:
DLList& DLList::operator=(const DLList& iList)
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
return *this;
}
这里是推送操作的代码:
void DLList::push(int data)
{
Node *n = new Node;
n->data = data;
n->next = NULL;
//n->random = NULL;
n->next = _head;
_head = n;
//cout << "_head" <<_head->data<< "head->next" << (_head->next ? _head->next->data : 0)<<endl;
}
这是主要代码(发生崩溃的地方):
DLList *d = new DLList();
d->push(10);
d->push(20);
d->push(30);
d->push(40);
d->setRandom();
d->display("Original list"); // Displays the original list fine
DLList *d1 = new DLList();
d1 = d;
d1->display("Cloned list"); //Displays the cloned list fine
delete d; // works fine
delete d1; // Crashes here due to segmentation fault, invalid pointer access during delete called as part of destructor)
析构函数代码(如果有帮助):
~DLList()
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
}
答案 0 :(得分:6)
您实际上没有使用赋值运算符!您只是将指针复制到另一个指针。 调试代码(或只是添加跟踪)会显示
d
和d1
的地址相同因此,当您删除第二个列表时,您会删除相同的地址两次。
你真的不需要new
:
DLList d;
d.push(10);
DLList d1 = d; // assignment is REALLY called
d1.display("Cloned list");
当你超出变量范围时,对象将被删除
如果您想在上下文中进行测试,请保留new
,更改
d1 = d;
通过
*d1 = *d;
激活赋值运算符。
另一个建议:分解你的拷贝代码,使其在赋值运算符和拷贝构造函数之间共享,并且删除代码应该在析构函数和赋值运算符之间共享(以避免在分配两次时发生内存泄漏):未经测试,不要&#39;如果它没有编译,请点燃我,告诉我我会修复它,我已经在这里过度转移了:))
DLList& DLList::operator=(const DLList& iList)
{
destroy(); // or you'll get memory leaks if assignment done twice
copy(iList);
return *this;
}
DLList& DLList::DLList(const DLList& iList)
{
_head = NULL; // set _head to NULL in all your constructors!!
copy(iList);
}
~DLList()
{
destroy();
}
void DLList::copy(const DLList& iList) // should be private
{
Node *t = iList.head();
while(t != NULL)
{
push(t->data);
t = t->next;
}
}
void DLList::destroy() // private
{
while(_head != NULL)
{
Node *temp = _head;
_head = _head->next;
delete temp; // crashes here during first iteration for the cloned list
}
_head = NULL; // calling destroy twice is harmless
}
答案 1 :(得分:2)
d1 = d;
不会复制DLList。相反,您只需将d1
指向d
指向的列表即可。因此,d1
和d
都指向同一个列表。在程序结束时,您将删除该列表两次,并使程序崩溃。
答案 2 :(得分:2)
如果您希望使用赋值运算符,则需要取消引用指针。见这里:
d1
在突出显示的行上,您将指针 d
设置为指向与delete
相同的位置。这意味着当您在代码末尾调用d
时,您尝试删除同一个对象(在这种情况下为DLList *d1 = new DLList();
*d1 = *d; // <------------- Note the dereference applied to BOTH lists.
d1->display("Cloned list"); //Displays the cloned list fine
)两次。
要修复代码,您应该取消引用指针:
Warning :-Presenting view controllers on detached view controllers is discouraged
或者,如果可以的话,应该完全避免使用指针。对于您的简单示例,您可以直接创建对象。
答案 3 :(得分:0)
您的问题是声明
d1 = d;
执行指针赋值,并使d1
指向与d
相同的对象。随后的delete
语句导致相同的对象(*d
)被释放两次。这是未定义的行为(其中一个症状就像你描述的那样崩溃)。
上面也没有调用DLList
的拷贝构造函数。如果这是你的意图,你需要做
*d1 = *d;
使d1
指向的对象成为d
指向的对象的副本。在这种情况下,两个delete
语句也是合适的。