使用智能指针的通用双链表

时间:2018-08-08 23:32:42

标签: c++ vector smart-pointers

我正在尝试使用智能指针实现通用的双链表。目前,我正在尝试编写push_back函数,但出现此错误:

1>------ Build started: Project: LinkedList, Configuration: Debug Win32 ------
1>main.cpp
1>c:\dev\linkedlist\linkedlist\doublelinkedlist.h(155): error C2679: binary '=': no operator found which takes a right-hand operand of type 'DoubleLinkedList<int>::Node *' (or there is no acceptable conversion)
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2309): note: could be 'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2247): note: or       'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(std::unique_ptr<_Ty,std::default_delete<_Ty>> &&) noexcept'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2173): note: or       'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(std::nullptr_t) noexcept'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\dev\linkedlist\linkedlist\doublelinkedlist.h(155): note: while trying to match the argument list '(std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>>, DoubleLinkedList<int>::Node *)'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\dev\linkedlist\linkedlist\doublelinkedlist.h(153): note: while compiling class template member function 'void DoubleLinkedList<int>::push_back(T &&)'
1>        with
1>        [
1>            T=int
1>        ]
1>c:\dev\linkedlist\linkedlist\main.cpp(97): note: see reference to function template instantiation 'void DoubleLinkedList<int>::push_back(T &&)' being compiled
1>        with
1>        [
1>            T=int
1>        ]
1>c:\dev\linkedlist\linkedlist\main.cpp(96): note: see reference to class template instantiation 'DoubleLinkedList<int>' being compiled
1>c:\dev\linkedlist\linkedlist\doublelinkedlist.h(159): error C2679: binary '=': no operator found which takes a right-hand operand of type 'DoubleLinkedList<int>::Node *' (or there is no acceptable conversion)
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2309): note: could be 'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2247): note: or       'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(std::unique_ptr<_Ty,std::default_delete<_Ty>> &&) noexcept'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2173): note: or       'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(std::nullptr_t) noexcept'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\dev\linkedlist\linkedlist\doublelinkedlist.h(159): note: while trying to match the argument list '(std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>>, DoubleLinkedList<int>::Node *)'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\dev\linkedlist\linkedlist\doublelinkedlist.h(163): error C2065: 'newnode': undeclared identifier
1>c:\dev\linkedlist\linkedlist\doublelinkedlist.h(164): error C2679: binary '=': no operator found which takes a right-hand operand of type 'DoubleLinkedList<int>::Node *' (or there is no acceptable conversion)
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2309): note: could be 'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2247): note: or       'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(std::unique_ptr<_Ty,std::default_delete<_Ty>> &&) noexcept'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.14.26428\include\memory(2173): note: or       'std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>> &std::unique_ptr<_Ty,std::default_delete<_Ty>>::operator =(std::nullptr_t) noexcept'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>c:\dev\linkedlist\linkedlist\doublelinkedlist.h(164): note: while trying to match the argument list '(std::unique_ptr<DoubleLinkedList<int>::Node,std::default_delete<_Ty>>, DoubleLinkedList<int>::Node *)'
1>        with
1>        [
1>            _Ty=DoubleLinkedList<int>::Node
1>        ]
1>Done building project "LinkedList.vcxproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

这是我要实现的功能:

template <class T>
void DoubleLinkedList<T>::push_back(T &&thedata) {
    std::unique_ptr<Node> newNode = std::make_unique<Node>(std::move(thedata));
    newNode->previous = std::move(tail.get());

    if (!head) {
        head = std::move(newNode);
        tail = head.get();
    }

    else {
        tail->next = std::move(newnode);
        tail = tail->next.get();
    }
}

错误发生在newNode->previous = std::move(tail.get());tail = tail->next.get();。我不知道如何解决此问题,以确保我为双重链接列表建立了正确的链接。

这是我初始化尾巴和头的类的样子:

class DoubleLinkedList {
private:

    struct Node {
        T data;
        std::unique_ptr<Node> next = nullptr;
        std::unique_ptr<Node> previous = nullptr;

    };
    std::unique_ptr<Node> head = nullptr;
    std::unique_ptr<Node> tail = nullptr;
};

这是我尝试使用push_back函数的时间:

#include <iostream>
#include <iterator>
#include <memory>
#include <utility>
#include <stdexcept>
#include <iosfwd>
#include <stdexcept>
#include <ostream>
#include "DoubleLinkedList.h"

int main(int argc, const char * argv[]) {


     ///////////////////////////////////////////////////////////////////////
     ///////////////////////////// Double Linked List //////////////////////
     ///////////////////////////////////////////////////////////////////////
     DoubleLinkedList<int> obj;
     obj.push_back(2);
     obj.push_back(4);
     obj.push_back(6);
     obj.push_back(8);
     obj.push_back(10);
     std::cout<<"\n--------------------------------------------------\n";
     std::cout<<"---------------displaying all nodes---------------";
     std::cout<<"\n--------------------------------------------------\n";
     std::cout << obj << "\n";


    std::cin.get();
}

2 个答案:

答案 0 :(得分:1)

如Jarod42所重申,请使用shared_ptr并使结构节点可访问。试试这个:

template <class T>
struct Node {
    Node(T val):data(val){}
    T data;
    std::shared_ptr<Node> next = nullptr;
    std::weak_ptr<Node> previous ; //weak_ptr to avoid cyclic reference

};

template <class T>
class DoubleLinkedList {
public:
    void push_back(T thedata);

    std::shared_ptr<Node<T>> head = nullptr;
    std::shared_ptr<Node<T>> tail = nullptr;
};

template <class T>
std::ostream& operator<<(std::ostream& os, DoubleLinkedList<T>& obj) {
    std::shared_ptr<Node<T>> node = obj.head;
    while (node!= nullptr) {
        os << node->data << std::endl;
        node = node->next;
    }
    return os;
}

template <class T>
void DoubleLinkedList<T>::push_back(T thedata) {
    std::shared_ptr<Node<T>> newNode = std::make_shared<Node<T>>(thedata);
    newNode->previous = tail;

    if (!head) {
        head = newNode;
        tail = head;
    }

    else {
        tail->next = newNode;
        tail = tail->next;
    }
}

int main()
{
    DoubleLinkedList<int> obj;
    obj.push_back(2);
    obj.push_back(4);
    obj.push_back(6);
    obj.push_back(8);
    obj.push_back(10);
    std::cout << "\n--------------------------------------------------\n";
    std::cout << "---------------displaying all nodes---------------";
    std::cout << "\n--------------------------------------------------\n";
    std::cout << obj << "\n";

    std::cin.get();
    return 0;
}

答案 1 :(得分:1)

由于周期的原因,双向链接列表不是智能指针(至少对于内部前/后链接)的理想选择。节点彼此之间不拥有所有权,并且由于没有所有权或层次结构关系,因此无法进行引用计数或类似的递减操作,以便在不再需要列表时可以回收内存。

但是,可以想到的是,可以将拥有的指针(唯一的或共享的)用于一个方向的链接,而将weak_ptrs用作另一方向的链接,以避免这些问题。这样可以建立清晰的父子关系,并使内存管理正常工作。

话虽如此,列表的客户当然可能希望使用智能指针来保存他们插入列表中的项目。我只是不会在列表内部使用它们。