C++ - 链表 - 无法创建临时节点

C++ - Linked List - Unable to create a temporary node

我正在尝试在我的打印函数中创建一个临时变量 'p'。 我收到 1 个编译器错误和 2 个我不知道如何处理的警告。

一旦我掌握了打印功能,大多数功能都留待以后填充。

我还重新定义了 cout<<&n 以打印出链表的值。

unique_ptr.h||In instantiation of 'typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = Node; _Args = {const std::unique_ptr<Node, std::default_delete<Node> >*}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<Node>]':|

Deque.cpp|46|required from here|

/usr/include/c++/6/bits/unique_ptr.h|787|error: invalid conversion from 'const std::unique_ptr<Node>*' to 'int' [-fpermissive]|
Node.h|15|note:   initializing argument 1 of 'Node::Node(int)'|

||=== 构建失败:1 个错误,2 个警告(0 分钟,0 秒)===|

Main.cpp

#include <iostream>
#include "Node.h"
#include "Deque.cpp"

using std::cout;
using std::endl;


std::ostream& operator<<(std::ostream& out, const Node& n) {
  return out << &n << ": " << n.val << " -> " << n.next.get();
}

int main()
{

      return 0;
}

Node.h

#ifndef NODE_H
#define NODE_H

#include <iostream>
#include <memory>

class Node {
 public:
 Node(const Node& n) : val{n.val}, next{}
  {
  }
 Node(int v, std::unique_ptr<Node> n) : val{v}, next{move(n)}
  {
  }
 Node(int v) : val{v}
  {
  }

 private:
  int val = 0;
  std::unique_ptr<Node> next = nullptr;

  friend class Deque;
  friend std::ostream& operator<<(std::ostream&, const Node&);
};

#endif

Deque.h

#include <memory>

class Deque{
    public:
        Deque() = default;
        Deque(const Deque&);
        ~Deque(); //must use constant space
        Deque& operator=(const Deque&); //we can use assignment in this assignement lols.



        void print_queue(const std::string& label) const; //prints all nodes in queue,
        //together with pointers to head and tail and also size of queue.
        //routine calls the node output function - not tested



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

    friend Node;


};

Deque.cpp

#include "Deque.h"
#include <memory>
using std::cout;
using std::endl;


void Deque::print_queue( const std::string& label) const
{
std::unique_ptr<Node> p = std::make_unique<Node>(&head);
cout<< "This is the linked list: " << endl;

while ( p != NULL)
    {
        cout<< &head;
    }

}

看看你的代码,我认为你应该多读两件事。 首先是 C++ 中 & 运算符的引用和多重含义。

当你有这样的功能时:

void f(const Type& param);

表示param是对const Type的引用。本例中的 & 声明了 param 一个引用。如果你想调用这个方法,你可以这样做:

Type value;
f(value);

请注意,参数 value 是按原样传递的,没有任何其他限定符。相反,如果您尝试调用函数,例如:

f(&value);

然后 & 表示 address of&value 不是引用,它是一个指针,它要求函数看起来像:

void f(Type *param);

这解释了您在编写此代码时遇到的错误:

std::unique_ptr<Node> p = std::make_unique<Node>(&head);

这里 head 是一个 std::unique_ptr<Node> 所以 &head 是指向 unique_ptr<Node> 的指针。这正是错误消息告诉您的内容:

invalid conversion from 'const std::unique_ptr<Node>*' to 'int'

它试图调用带有 int 参数的 Node 构造函数,但无法将指向 unique_ptr 的指针转换为 int

您应该阅读的第二件事是 unique_ptr 本身。总之,unique_ptr是一个单一所有权的智能指针,它不能被复制,你不能非要unique-ptr管理同一个对象。 这就是为什么你不能在你的代码中这样做:

std::unique_ptr<Node> p = head;

这种情况下的错误消息基本上告诉你 unique_ptr.

没有复制构造函数

因为您不能复制 unique_ptrs,所以遍历以您编写的方式实现的链表无法像您尝试使用的通常的家庭作业一样完成。当您在列表中执行其他操作时,例如插入或删除节点,您还必须更加认真地思考。

但是让我们坚持遍历列表。您无法复制 unique_ptr,因此您必须使用引用或原始指针来访问它们。

使用引用

这个方法也不简单,因为引用在定义后不能"reassigned"。所以你可以尝试递归地做,例如:

void printNodeAndGoNext(const std::unique_ptr<Node> &node)
{
    if (node)
    {
        std::cout << node->value;
        printAndGoNext(node->next);
    }
}

void print()
{
    printNodeAndGoNext(head);
}

这仅使用对 unique_ptr 的引用,不需要创建任何节点副本。 但与递归函数一样,它无法扩展。不要这样做。

使用指针

您可以使用原始非拥有指针指向 unique_ptr 本身或它们管理的底层节点。

第一个版本看起来像这样:

void print()
{
    const std::unique_ptr<Node> *node = &head;
    while(node)
    {
        std::cout << (*node)->value;
        node = &((*node)->next);
    }
}

注意 *& 以及您获得的实际数据类型。

第二个版本,使用指向实际节点的原始指针:

void print()
{
    const Node *node = head.get();
    while (node)
    {
        std::cout << node->value;
        node = node->next.get();
    }
}

在所有这些之间,最后一个版本将是首选。如果您稍微小心一点,使用指向由拥有 unique_ptrs 管理的对象的原始非拥有指针是非常好的和安全的。

免责声明

上面的代码片段只是为了说明要点,您必须根据自己的情况调整思路并实际编写代码。

你以后会遇到的问题

我已经提到了其中的一些。您必须使用 unique_ptr.

的独特属性来实现标准列表操作,例如插入和删除

要考虑(和修复)的另一个方面与递归有关。更具体地说,当你有一个像这样实现的列表并且它有几个节点(数千个节点,数万个,数百万个等)并且你想销毁它时会发生什么?