C ++ - 为链接列表中的unique_ptr节点分配原始指针

时间:2016-10-19 21:09:48

标签: c++ pointers types linked-list nodes

我试图弄清楚如何在删除链表中的节点后将我的尾部原始指针更新为新尾部。 (是作业)

我将头部和尾部定义为

    std::unique_ptr<Node> head ;
    Node* tail ;

在我从后面删除节点的功能中,我有以下实现。

int Deque::remove_back(){
if (empty()) {throw std::runtime_error(std::string("Empty"));};

std::unique_ptr<Node> old;

Node* p = head.get();

int return_value = tail->val;

while (p->next != tail)
{p = p->next)}

old = move(tail);
tail = p;

return return_value;
}

所以tail是Node类型的原始指针。 P是Node类型的原始指针。

Head是Node类型的唯一指针。

我设置p = head.get()

所以现在p指向头

p = p-&gt; next应该迭代我的节点。

问题在于p->next != tail

p-&gt; next是指向p后面的下一个节点的指针。

我试图将指向节点的指针设置为等于node(tail)类型的原始指针。

它告诉我我不能这样做。

我相信它是由于p-&gt;接下来没有变成拥有指针而不是观察我声明的指针。

错误:

Deque.cpp|68|error: no match for 'operator!=' (operand types are 'std::unique_ptr<Node>' and 'Node*')|

Deque.cpp|69|error: cannot convert 'std::unique_ptr<Node>' to 'Node*' in assignment|

Deque.cpp|71|error: no match for 'operator=' (operand types are 'std::unique_ptr<Node>' and 'std::remove_reference<Node*&>::type {aka Node*}')|

2 个答案:

答案 0 :(得分:4)

错误消息暗示Node::nextstd::unique_ptr<Node>。您无法直接将std::unique_ptr与原始指针进行比较/分配。您需要使用std::unique_ptr::get()方法:

while (p->next.get() != tail) {
    p = p->next.get();
}

此外,当列表中只有一个节点(head == tail)时,您的循环不会考虑在内。 p->next将在第二次迭代时发生nullptr并崩溃。由于您要删除列表中的最后一个节点,因此您需要将head重置为nullptr。无论哪种方式,在将p指定为新tail时,您需要将p->next重置为nullptr,以便它不再指向旧节点。

试试这个:

int Deque::remove_back(){
    if (empty()) {
        throw std::runtime_error("Empty");
    }

    int return_value = tail->val;

    if (!head->next) {
        head = nullptr; // or: head.reset();
        tail = nullptr;
    }
    else {
        Node* p = head.get();
        Node *prev = p;
        while (p->next->next) {
            p = p->next.get();
            prev = p;
        }
        tail = prev;
        tail->next = nullptr; // or: tail->next.reset();
    }

    return return_value;
}

话虽如此,在链表实现中使用std::unique_ptr可能会很棘手。如果你想自动销毁节点,你可以使用原始指针并将列表包装在一个类中,当它自身被销毁时销毁它们,然后remove_back()可以破坏被删除的节点。

STL已经有这样的类:std::list(双链接)和std::forward_list(单链接)。您应该使用它们而不是手动列表实现。

答案 1 :(得分:1)

当只有一个元素时,您的功能有问题。你需要一个条件(代码重复)或使它更复杂一点:

int Deque::remove_back(){
    if (empty()) {throw std::runtime_error(std::string("Empty"));};

    Node *newtail = nullptr;
    std::unique_ptr<Node> *curr = &head;
    while( curr->get() != tail ) {
        newtail = curr->get();
        curr = &(*curr)->next;
    }

    tail = newtail;
    std::unique_ptr<Node> tmp = std::move( *curr );

    return tmp->val;
}