我正在尝试创建一个复制构造函数,以便复制向量。我怀疑它不起作用,因为复制构造函数不是复制新节点,而是简单地复制指向它们的指针,所以节点被删除了两次。我不确定我的复制构造函数出了什么问题。感谢您的帮助。
#include <iostream>
using namespace std;
struct node{
public:
node(int n){
node* ptr = this;
data = 0;
for (int t=0; t<n-1; t++){
ptr -> next = new node(1);
ptr = ptr -> next;
ptr -> data = 0;
}
ptr -> next = NULL;
}
node(node &obj){
delete next;
node* ptr = this;
node* optr = &obj;
while (true){
ptr -> data = optr -> data;
optr = optr -> next;
if (optr == NULL) break;
ptr -> next = new node(1);
ptr = ptr -> next;
}
}
~node(){
if (next != NULL) delete next;
}
private:
double data;
node* next;
};
void func(node a){
node b(1);
b = a;
}
int main(){
node v(3);
func(v);
}
感谢
一些东西跳了出来:
首先,如果您在开发环境的调试器中运行这段测试代码,您可以看到发生了什么,并更快地修复它。调试器的使用是高效程序员的一项基本技能,所以你越早学会越好。
第二个是意识形态问题,如果你不同意,请忽略我。node
不能具有链接列表可以具有的关于列表状态的信息,因此节点不应在未经链接列表指示的情况下链接自己、取消链接自己或delete
链接的node
。虽然自我管理行为很有用,但它并不总是列表中正确的行为。我发现最好保持node
真的很笨。
第三,在构造函数中,在初始化变量之前,不会初始化任何变量。你不能指望它们有有用或可预测的价值,所以
node(node &obj){
delete next;
进入未定义行为领域。next
的值尚未分配,因此它是未知的,如果您尝试delete
,则不可能准确预测会发生什么。
解决方案:不要delete
。
node(node &obj)
{
node* ptr = this;
node* optr = &obj;
while (true)
{
ptr->data = optr->data;
optr = optr->next;
if (optr == NULL)
break;
ptr->next = new node(1);
ptr = ptr->next;
}
}
这里可以做一些改进,但这超出了问题的范围。
附带说明:
void func(node a)
通过值传递CCD_ 8。这可能会提前一点触发复制构造函数。你可能想在这里通过参考:
void func(node &a)
最后,
node b(1);
b = a;
不触发复制构造函数。
node b(1);
构造没有附加链路的CCD_ 9。
b = a;
使用赋值运算符operator=
将a
复制到b
中。
但尚未定义operator=
。这违反了"三条规则"。什么是"三条规则"?阅读链接并找出答案。
对您来说,这意味着要复制next
指针,而不是next
node
。现在有两个node
指向链接的node
,换句话说,是同一个列表,这很糟糕。删除一个,就删除了另一个的内容,使另一个无效。
node & operator=(node other) // pass by value copies the node
{
delete next; // prevent leak of additional nodes. The smart destructor helps here.
data = other.data; // copy data
next = other.next; // steal remaining links from other. to save further copying
other.next = nullptr; // prevent destruction of the remaining links when
// other goes out of scope
return *this;
}
我们通过引用传递使用复制构造函数,而不是复制复制构造函数中复制完成的工作。
作为一个有用的旁注,
node b = a;
将为您调用复制构造函数,并使用a
初始化b
,而无需事先构造"临时"b
。
我不关心任何进一步的问题,因为它们无法用所提供的框架进行测试。