C++ 重载运算符=在单链表中
我当前在将内容从一个列表复制到另一个列表时遇到问题。编译时,所有值都显示为0。我认为当复制构造函数正在使用其代码时,重载赋值运算符可能有问题 复制构造函数C++ 重载运算符=在单链表中,c++,C++,我当前在将内容从一个列表复制到另一个列表时遇到问题。编译时,所有值都显示为0。我认为当复制构造函数正在使用其代码时,重载赋值运算符可能有问题 复制构造函数 ListOfDoubles::ListOfDoubles(const ListOfDoubles&e):head(NULL) { if (this != &e) { *this = e; } } 重载运算符= const ListOfDoubles& ListOfDoubles::operator=(cons
ListOfDoubles::ListOfDoubles(const ListOfDoubles&e):head(NULL) {
if (this != &e) {
*this = e;
}
}
重载运算符=
const ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles
&doubleslist)
{
DoubleListNode *cpyPtr = NULL;
DoubleListNode* orgPtr = doubleslist.head;
if (this != &doubleslist)
{
while (head != NULL)
{
ListOfDoubles::~ListOfDoubles();
}
while (orgPtr != NULL)
{
if (head == NULL)
{
head = cpyPtr = new DoubleListNode(orgPtr->data);
}
else
{
cpyPtr->next = new DoubleListNode(orgPtr->data);
cpyPtr = cpyPtr->next;
}
orgPtr = orgPtr->next;
}
}
return *this;
}
通用复制逻辑类似于:
DoubleListNode * from = source.head; // copying from
DoubleListNode ** to = &head; // pointer to where we want to copy to
while (from != nullptr) // keep going until end of list. You did mark
// the end of the list, didn't you?
{
*to = new node(*from); //copy construct a new node around from and store it at to
to = &(*to)->next; // advance to
from = from.next; // advance from
}
*to = nullptr; // all done. Terminate list.
真正的魔力就在这里的双指针上:DoubleListNode**to
通过有一个指向指针的指针,我们不在乎是指向头
,还是指向另一个节点的下一个
,或者你有什么。这只是另一个节点,因此没有特殊情况需要说明
您可以在复制构造函数和赋值运算符中执行上述操作,但最好不要重复自己的操作,并将其放入由复制构造函数和赋值运算符调用的函数中。请注意,对于复制构造函数中预先存在的数据(例如,列表将为空)和赋值运算符(例如,列表可能不为空,请在开始之前清除它并释放所有节点),需要考虑不同的假设
如上文评论所述,主要的替代方案是使用。因此,上面的复制循环只存在于复制构造函数中 通用复制逻辑类似于:
DoubleListNode * from = source.head; // copying from
DoubleListNode ** to = &head; // pointer to where we want to copy to
while (from != nullptr) // keep going until end of list. You did mark
// the end of the list, didn't you?
{
*to = new node(*from); //copy construct a new node around from and store it at to
to = &(*to)->next; // advance to
from = from.next; // advance from
}
*to = nullptr; // all done. Terminate list.
真正的魔力就在这里的双指针上:DoubleListNode**to
通过有一个指向指针的指针,我们不在乎是指向头
,还是指向另一个节点的下一个
,或者你有什么。这只是另一个节点,因此没有特殊情况需要说明
您可以在复制构造函数和赋值运算符中执行上述操作,但最好不要重复自己的操作,并将其放入由复制构造函数和赋值运算符调用的函数中。请注意,对于复制构造函数中预先存在的数据(例如,列表将为空)和赋值运算符(例如,列表可能不为空,请在开始之前清除它并释放所有节点),需要考虑不同的假设
如上文评论所述,主要的替代方案是使用。因此,上面的复制循环只存在于复制构造函数中 复制构造函数的输入参数永远不会是正在构造的对象,因此请检查
this!=&复制构造函数中的e
是多余的
此外,直接手动调用析构函数是非法的,除非内存分配了placement new
,而您没有使用该内存。您需要使用delete
销毁节点实例
通常,您不应该按照操作符=
实现复制构造函数,而应该反过来实现。让复制构造函数完成复制源值的工作,然后让operator=
复制源列表并获得复制数据的所有权。这通常被称为“复制并交换”成语
请尝试以下方法:
ListOfDoubles::ListOfDoubles()
: head(NULL)
{
}
ListOfDoubles::ListOfDoubles(const ListOfDoubles &e)
: head(NULL)
{
DoubleListNode *cpyPtr = NULL;
DoubleListNode *prevPtr = NULL;
DoubleListNode *orgPtr = e.head;
while (orgPtr)
{
cpyPtr = new DoubleListNode(orgPtr->data);
if (!head)
head = cpyPtr;
if (prevPtr)
prevPtr->next = cpyPtr;
prevPtr = cpyPtr;
orgPtr = orgPtr->next;
}
/* alternatively:
DoubleListNode **cpyPtr = &head;
DoubleListNode *orgPtr = e.head;
while (orgPtr)
{
*cpyPtr = new DoubleListNode(orgPtr->data);
cpyPtr = &((*cpyPtr)->next);
orgPtr = orgPtr->next;
}
*cpyPtr = NULL;
*/
}
ListOfDoubles::~ListOfDoubles()
{
DoubleListNode *orgPtr = head;
DoubleListNode *nextPtr;
while (orgPtr)
{
nextPtr = orgPtr->next;
delete orgPtr;
orgPtr = nextPtr;
}
}
ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles &doubleslist)
{
if (this != &doubleslist)
{
ListOfDouble tmp(doubleslist);
std::swap(head, tmp.head);
}
return *this;
}
复制构造函数的输入参数永远不会是正在构造的对象,因此请检查
this!=&复制构造函数中的e
是多余的
此外,直接手动调用析构函数是非法的,除非内存分配了placement new
,而您没有使用该内存。您需要使用delete
销毁节点实例
通常,您不应该按照操作符=
实现复制构造函数,而应该反过来实现。让复制构造函数完成复制源值的工作,然后让operator=
复制源列表并获得复制数据的所有权。这通常被称为“复制并交换”成语
请尝试以下方法:
ListOfDoubles::ListOfDoubles()
: head(NULL)
{
}
ListOfDoubles::ListOfDoubles(const ListOfDoubles &e)
: head(NULL)
{
DoubleListNode *cpyPtr = NULL;
DoubleListNode *prevPtr = NULL;
DoubleListNode *orgPtr = e.head;
while (orgPtr)
{
cpyPtr = new DoubleListNode(orgPtr->data);
if (!head)
head = cpyPtr;
if (prevPtr)
prevPtr->next = cpyPtr;
prevPtr = cpyPtr;
orgPtr = orgPtr->next;
}
/* alternatively:
DoubleListNode **cpyPtr = &head;
DoubleListNode *orgPtr = e.head;
while (orgPtr)
{
*cpyPtr = new DoubleListNode(orgPtr->data);
cpyPtr = &((*cpyPtr)->next);
orgPtr = orgPtr->next;
}
*cpyPtr = NULL;
*/
}
ListOfDoubles::~ListOfDoubles()
{
DoubleListNode *orgPtr = head;
DoubleListNode *nextPtr;
while (orgPtr)
{
nextPtr = orgPtr->next;
delete orgPtr;
orgPtr = nextPtr;
}
}
ListOfDoubles& ListOfDoubles::operator=(const ListOfDoubles &doubleslist)
{
if (this != &doubleslist)
{
ListOfDouble tmp(doubleslist);
std::swap(head, tmp.head);
}
return *this;
}
ListOfDoubles::~ListOfDoubles()代码>坏主意。你几乎从来都不想自己调用析构函数,这看起来也不罕见。它会导致未定义的行为调用析构函数,然后继续使用该对象。你完全是在倒行逆施;如果你想在CC和op=之间共享代码,那么就正确地实现CC,让op=复制并交换代码。这对你来说可能有些过分,但编写起来相当容易,证明起来也非常容易:@FrançoisAndrieux Holy smurf。这合法吗?哇。ListOfDoubles::~ListOfDoubles()代码>坏主意。你几乎从来都不想自己调用析构函数,这看起来也不罕见。它会导致未定义的行为调用析构函数,然后继续使用该对象。你完全是在倒行逆施;如果你想在CC和op=之间共享代码,那么就正确地实现CC,让op=复制并交换代码。这对你来说可能有些过分,但编写起来相当容易,证明起来也非常容易:@FrançoisAndrieux Holy smurf。这合法吗?哇!