我目前正在建立一个名为Sequence的链接列表类。有四个专用节点-headPtr,tailPtr,光标(当前节点)和前驱(上一个节点)。

当光标是列表中的最后一项时,我的副本构造函数运行良好,但是由于某种原因,当光标位于列表的中间时,该函数从不退出while循环。

这是复制构造函数:

Sequence::Sequence(const Sequence& copyMe) {
        copy(copyMe);
    }

void Sequence::copy(const Sequence& copyMe) {

        numitems = 0;

        if (copyMe.headPtr == nullptr) {
            cursor = precursor = headPtr = tailPtr = nullptr;
        }
        else {

            // allocate a new node for the new sequence
            node* newPtr = new node;
            newPtr -> data = copyMe.headPtr -> data;
            numitems++;

            // start the new sequence with this node
            headPtr = newPtr;
            precursor = nullptr;
            cursor = headPtr;
            tailPtr = headPtr;

            // create a node to traverse the origin sequence
            node* originPtr = copyMe.headPtr -> next;

            while (originPtr != nullptr) {

                // add node to the new list, make it the current, & assign data
                newPtr->next = new node;
                newPtr = newPtr->next;
                newPtr->data = originPtr->data;
                numitems++;

                // Correct cursor and precursor positions
                if(originPtr == copyMe.cursor) {
                    this->cursor = newPtr;
                }
                else if (originPtr == copyMe.precursor) {
                    this->precursor = newPtr;
                }
                originPtr = originPtr->next;

                // if the thing being copied is the last thing, make it tailptr
                if (originPtr == nullptr) {

                    tailPtr = newPtr->next;
                    cout << "tail assigned" << endl;

                    newPtr->next = nullptr;
                    originPtr = nullptr;
                }
            }
        }
    }

这是驱动程序:


    const size_t TESTSIZE = 30;
    Sequence original; // A Sequence that we'll copy.
    double items[2 * TESTSIZE];
    size_t i;

    // Set up the items array to conatin 1...2*TESTSIZE.
    for (i = 1; i <= 2 * TESTSIZE; i++)
        items[i - 1] = i;

    // This section works fine //
    // Test copying of an empty Sequence. After the copying, we change original.
    cout << "Copy constructor test: for an empty Sequence." << endl;
    Sequence copy1(original);
    original.attach(1); // Changes the original Sequence, but not the copy.

    // Test copying of a Sequence with current item at the tail.
    cout << "Copy constructor test: for a Sequence with cursor at tail." << endl;
    for (i = 2; i <= 2 * TESTSIZE; i++) {
        original.attach(i);
    }
    Sequence copy2(original);
    original.remove_current();
    original.start();
    original.advance();
    original.remove_current(); // Delete 2 from original, but not the copy.

    // This section gets stuck in the while loop of my copy constructor //
    // Test copying of a Sequence with cursor near the middle.
    cout << "Copy constructor test: with cursor near middle." << endl;
    original.insert(2);
    for (i = 1; i < TESTSIZE; i++)
        original.advance();
    // Cursor is now at location [TESTSIZE] (counting [0] as the first spot).
    Sequence copy3(original);


我很困惑,为什么光标的位置会影响originPtr的前进,为什么originPtr不会变为null并分配尾部。我尝试输出它指向的内容,但似乎它只是以循环方式不断前进通过内存插槽。一旦达到60,它将直接从2开始相加而不是终止。

谢谢你的帮助!

编辑:
这是在添加一些cout语句后最后使用游标时输出的样子:
Copy constructor test: for a Sequence with cursor at tail.
Copy constructor test: for a Sequence with cursor at tail.
newPtr is: 0x7fa6dcd00140 and originPtr is: 0x7fa6dcd00000
newPtr is: 0x7fa6dce00010 and originPtr is: 0x7fa6dcd00020
newPtr is: 0x7fa6dce00020 and originPtr is: 0x7fa6dcd00030
newPtr is: 0x7fa6dce00030 and originPtr is: 0x7fa6dcd00040
newPtr is: 0x7fa6dce00040 and originPtr is: 0x7fa6dcd00050
newPtr is: 0x7fa6dce00050 and originPtr is: 0x7fa6dcd00060
newPtr is: 0x7fa6dce00060 and originPtr is: 0x7fa6dcd00070
newPtr is: 0x7fa6dce00070 and originPtr is: 0x7fa6dcd00080
newPtr is: 0x7fa6dce00080 and originPtr is: 0x7fa6dcd00090
newPtr is: 0x7fa6dce00090 and originPtr is: 0x7fa6dcd000a0
newPtr is: 0x7fa6dce000a0 and originPtr is: 0x7fa6dcd000b0
newPtr is: 0x7fa6dce000b0 and originPtr is: 0x7fa6dcd000c0
newPtr is: 0x7fa6dce000c0 and originPtr is: 0x7fa6dcd000d0
newPtr is: 0x7fa6dce000d0 and originPtr is: 0x7fa6dcd000e0
newPtr is: 0x7fa6dce000e0 and originPtr is: 0x7fa6dcd000f0
newPtr is: 0x7fa6dce000f0 and originPtr is: 0x7fa6dcd00100
newPtr is: 0x7fa6dce00100 and originPtr is: 0x7fa6dcd00110
newPtr is: 0x7fa6dce00110 and originPtr is: 0x7fa6dcd00120
NULL REACHED
tail assigned

与光标位于中间的下一个测试
newPtr is: 0x7fa6dcf00030 and originPtr is: 0x7fa6dcd00000
newPtr is: 0x7fa6dcf00040 and originPtr is: 0x7fa6dcd00020
newPtr is: 0x7fa6dcf00050 and originPtr is: 0x7fa6dcd00030
newPtr is: 0x7fa6dcf00060 and originPtr is: 0x7fa6dcd00040
newPtr is: 0x7fa6dcf00070 and originPtr is: 0x7fa6dcd00050
newPtr is: 0x7fa6dcf00080 and originPtr is: 0x7fa6dcd00060
newPtr is: 0x7fa6dcf00090 and originPtr is: 0x7fa6dcd00070
newPtr is: 0x7fa6dcd00010 and originPtr is: 0x7fa6dcd00080
newPtr is: 0x7fa6dcd00120 and originPtr is: 0x7fa6dcd00090
newPtr is: 0x7fa6dcd00150 and originPtr is: 0x7fa6dcd000a0
newPtr is: 0x7fa6dcd00160 and originPtr is: 0x7fa6dcd000b0
newPtr is: 0x7fa6dcd00170 and originPtr is: 0x7fa6dcd000c0
newPtr is: 0x7fa6dcd00180 and originPtr is: 0x7fa6dcd000d0
newPtr is: 0x7fa6dcd00190 and originPtr is: 0x7fa6dcd000e0
newPtr is: 0x7fa6dce00120 and originPtr is: 0x7fa6dcd000f0
newPtr is: 0x7fa6dce00130 and originPtr is: 0x7fa6dcd00100
newPtr is: 0x7fa6dce00140 and originPtr is: 0x7fa6dcd00110
newPtr is: 0x7fa6dce00150 and originPtr is: 0x7fa6dcd00120
newPtr is: 0x7fa6dce00160 and originPtr is: 0x7fa6dcd00150
newPtr is: 0x7fa6dce00170 and originPtr is: 0x7fa6dcd00160
newPtr is: 0x7fa6dce00180 and originPtr is: 0x7fa6dcd00170
newPtr is: 0x7fa6dce00190 and originPtr is: 0x7fa6dcd00180
newPtr is: 0x7fa6dce001a0 and originPtr is: 0x7fa6dcd00190
newPtr is: 0x7fa6dce001b0 and originPtr is: 0x7fa6dce00120
newPtr is: 0x7fa6dce001c0 and originPtr is: 0x7fa6dce00130
newPtr is: 0x7fa6dce001d0 and originPtr is: 0x7fa6dce00140
newPtr is: 0x7fa6dce001e0 and originPtr is: 0x7fa6dce00150
newPtr is: 0x7fa6dce001f0 and originPtr is: 0x7fa6dce00160
newPtr is: 0x7fa6dce00200 and originPtr is: 0x7fa6dce00170
newPtr is: 0x7fa6dce00210 and originPtr is: 0x7fa6dce00180
newPtr is: 0x7fa6dce00220 and originPtr is: 0x7fa6dce00190
newPtr is: 0x7fa6dce00230 and originPtr is: 0x7fa6dce001a0
// and so on forever because its stuck in a loop and endlessly advancing somehow

最佳答案

复制构造函数的正确语法是:

Sequence::Sequence(const Sequence& copyMe) {...}

你写:
void Sequence::copy(const Sequence& copyMe) {...}

这意味着您定义了一个成员函数而不是构造函数。因此,永远不会调用您的构造函数。创建copy1,copy2和copy3时,将使用默认构造函数。

更新
if (originPtr == nullptr) {

  tailPtr = newPtr->next; // newPtr->next is not initialized here
                          // consider tailPtr = newPtr instead
  cout << "tail assigned" << endl;

  newPtr->next = nullptr; // good
  originPtr = nullptr;    // originPtr is nullptr here because of if condition
}

UPDATE2

我无法检查您移动光标的当前位置和先前位置的实现,但是请注意,在您的复制构造函数中,您假定当前指针和先前指针始终不同。
else if (originPtr == copyMe.precursor) { // consider removing 'else' here

UPDATE3
Sequence copy2(original);
original.remove_current(); // here you remove the last element

看来问题出在remove_current()中。构造函数中的循环不依赖于光标的位置。但这取决于原始序列的node-> next值。因此,创建副本中的错误不会导致无限循环。无限循环的唯一原因是格式不正确的原始序列。我怀疑您从序列中删除了最后一个元素后,忘记了更新最后一个节点的next值。在您发布remove_current()的代码之前,我无法证明我的话。

UPDATE4
void Sequence::remove_current() {
        if (is_item()) {

            node* temp;
            temp = cursor;

            if (cursor == headPtr && cursor == tailPtr) {
                cursor = nullptr;
                precursor = nullptr;
                headPtr = nullptr;
                tailPtr = nullptr;
            }
            else if (cursor == headPtr) {
                headPtr = cursor->next;
                cursor = headPtr;
                precursor = nullptr;
            }
            else {
                if (cursor == tailPtr) {
                    precursor->next = nullptr;
                    tailPtr = precursor;
                    cursor = precursor;
                    if (precursor == headPtr) {
                        precursor = nullptr;
                    }
                    else {
                        for(precursor = headPtr; precursor->next->next; precursor = precursor->next);
                    }
                }
                else {
                    precursor->next = cursor->next;
                    cursor = cursor->next;

                }
            }
            delete temp;
            numitems--;
        }
    }

08-27 22:19
查看更多