0

所以,我正在尝试在我正在编写的链接列表类中覆盖 operator=,但由于某种原因不断遇到这个奇怪的问题。

List& List::operator=(const List& copyList){
if(copyList.head != nullptr){
    makeEmpty();   // clears *this from any previous nodes
    cout << "if statement " << endl;
    head = new Node; // create a new node for head
    head -> data = copyList.head -> data; // copy the first data of copylist
    Node* pnew = head; // a temp node to traverse the new linkedlist
    assert(head != nullptr);
    Node* current2 = copyList.head;
    current2 = current2 -> next;
    while(current2 != NULL && pnew != NULL){
        cout << "entering while loop " << endl;
        pnew-> next = new Node;
        pnew -> next->data = current2 ->data;
        cout << "pnew next data " << *(pnew -> next->data)  << endl;
        assert(pnew-> next != nullptr);
        pnew = pnew -> next;
        current2 = current2 -> next;
        cout << "after current2" << endl;
    }
     pnew -> next = NULL;

}else{
    cout << "else statement " << endl;
    head = nullptr;
}
cout<< "printing out copylist"<< endl << copyList << endl;
cout<< "printing current list: " << endl << *this << endl;
return *this;

}

所以,这是我必须测试运算符覆盖的代码:

cout << "mylist:" << endl << mylist << endl;
   cout << "mylist4:" << endl << mylist4 << endl;
   mylist = mylist4;
   cout << "mylist:" << endl;
   cout << mylist << endl;
   cout << "mylist4:" << endl;
   cout << mylist4 << endl;

这是输出:

mylist:
10 f
16 u
20 n
25 !

mylist4:
14 s
15 t
16 u
18 f
19 f
25 !

if statement
entering while loop
pnew next data 15 t

after current2
entering while loop
pnew next data 16 u

after current2
entering while loop
pnew next data 18 f

after current2
entering while loop
pnew next data 19 f

after current2
entering while loop
pnew next data 25 !

after current2
printing out copylist
14 s
15 t
16 u
18 f
19 f
25 !

printing current list:
14 s
15 t
16 u
18 f
19 f
25 !
*crashes right here*

我一直试图找出这个问题大约 3 天。任何帮助将不胜感激。提前致谢!

编辑:这是构造函数(析构函数是编译器的默认析构函数):

NodeData::NodeData(int n, char c)  { 
    num = n; ch = c; 
} 

EDIT2:经过仔细检查,我发现了问题。问题是我没有将头的最后一个节点,即while循环之后的pnew指向null。这解决了这个问题。感谢大家的支持。

4

2 回答 2

2

你可以控制你的 Node 类,它应该透明地支持复制构造和赋值运算符,或者如果需要你自己动手。鉴于此,我同意 Dietmar 的观点,即利用 copy-ctor/swap/destructor 机制是理想的方法。

如果您坚持手动执行此操作,则以下是执行此操作的一种方法。您的实施使这需要的困难得多。

List& List::operator=(const List& copyList)
{
    List tmp;
    Node **dst = &tmp.head;
    const Node* src = copyList.head;
    while (src)
    {
        *dst = new Node(*src);     // invoke Node copy-ctor
        src = src->next;           // advance source
        (*dst)->next = nullptr;    // break link to original next
        dst = &(*dst)->next;       // move target to next pointer
    }

    // tmp now has a copy of the source list
    //  swap its head pointer with ours.
    std::swap(tmp.head, head);

    // upon return, the tmp object that now holds our
    //  original list will clean it up. we own the
    //  new list form this point on. 
    return *this;
}

这个怎么运作

指向指针的指针dst总是保存下一个要填充新节点的指针的地址。最初它保存本地List tmp对象的头指针的地址。. 当我们添加节点时,它会更新为始终保存next最后添加的节点的指针地址。通过这样做,我们会自动获得前向链接。一旦我们完成复制,tmp现在是源的副本。然后我们用自己的交换头指针。这反过来又交换了谁拥有哪个列表。当tmp在函数退出时被销毁时,它将与它一起销毁我们的旧列表。我们保留head指针指向的新列表。

以上假设您使用的是默认的 copy-ctor Node,这意味着制作副本将复制数据值下一个链接,后者是您不想要的,因此嵌入了链接中断。如果您实际实现Node::Node(const Node&)在复制后始终将链接设置为 NULL,则可以消除链接中断。即,您的Node复制构造函数应如下所示:

Node::Node(const Node& arg)
    : data(arg.data)
    , next()
{
}

这确保了一个干净的(data无论如何都可以复制的干净)副本,不会意外链接到原始的argnext 指针。

综上所述,Dietmar 的答案是最正确的,我相应地投了赞成票。如果这对您有帮助,请考虑对其进行投票,但他很容易成为理想的解决方案。

于 2013-10-26T19:23:21.353 回答
2

无需仔细研究实现(当我发现makeEmpty()它确保赋值运算符在没有任何充分理由的情况下不会是强异常安全时,我就停下来了):实现赋值运算符的最简单方法是利用复制构造函数,析构函数,通常是一个简单的编写函数swap()。除了类名之外,所有类的实现看起来都一样:

T& T::operator= (T other) {
    other.swap(this);
    return *this;
}

请注意,按值传递参数故意的:这是实际发生值的地方。与复制相比,T const&它的优点是在某些情况下可以省略实际复制。

于 2013-10-26T19:04:58.700 回答