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

时间:2016-10-11 00:05:08

标签: c++ variables linked-list smart-pointers singly-linked-list

我试图创建一个临时变量' p'在我的打印功能。 我收到一个编译错误和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;
    }

}

1 个答案:

答案 0 :(得分:1)

查看您的代码,我认为您应该阅读的内容有两个。 第一个是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);

此处headstd::unique_ptr<Node>,因此&head是指向unique_ptr<Node>的指针。这正是错误消息告诉您的内容:

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

它试图调用Node构造函数采用int参数,但无法将指针转换为unique_ptrint

您应该阅读的第二件事是unique_ptr本身。简而言之,unique_ptr是单一所有权的智能指针,无法复制,您无需unique-ptr来管理同一个对象。 这就是您不能在代码中执行此操作的原因:

std::unique_ptr<Node> p = head;

在这种情况下,错误消息基本上告诉您unique_ptr没有复制构造函数。

因为你无法复制unique_ptr,所以以你正在编写的方式遍历链接列表是不可能按照你正在尝试的常规作业方式完成的。你将会当你在列表上实现其他操作时,也必须更加思考,比如插入或删除节点。

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

使用参考

此方法也不简单,因为在定义引用后不能“重新分配”引用。所以你可以尝试递归地做,例如:

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_ptr所管理的对象是完全正确和安全的。

<强>声明

上面的代码片段只是为了说明这些要点,你必须调整这些想法并实际为你的情况编写代码。

您将面临的未来问题

我已经提到了其中一些。您必须使用unique_ptr的唯一属性来实现标准列表操作,例如插入和删除。

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