共享指针交换方法标识更改

shared pointer swap method identity change

背景: 我不知道是什么原因导致我对此进行试验,但我正在尝试测试内部使用智能指针的容器化 linked 列表。

这是回复link: https://repl.it/@BasavarajNagar/GoodnaturedGlisteningSection-1

#include <memory>

using namespace std;

template<typename T>
class linkedlist {
  private:

  class node {
    public:
      T data;
      shared_ptr<node> next;
      node(T data) {
        this->data = data;
      }
  };

  // non const unique ptr
  shared_ptr<node> head;

  public:
  void add(T data) {
    cout<< "adding " << endl;// + data << endl;

    if (head == nullptr) {
      head = shared_ptr<node>(new node(data));
      return;
    }

    shared_ptr<node> cursor;
    cursor.swap(head);

    // this works well
    while (cursor != nullptr) {
      cout << cursor->data << endl;
      cursor = cursor->next;
    }
    cout << data << endl;
    // this is the problematic assignment
    cursor = shared_ptr<node>(new node(data));
  }

  void trace() {
    shared_ptr<node> cursor;
    cursor.swap(head);

    cout << "trace" << endl;
    while (cursor != nullptr) {
      cout << cursor->data << endl;
      cursor = cursor->next;
    }
  }
};

int main() {
  std::cout << "Hello World!\n";

  linkedlist<int> ll;
  ll.add(22);
  ll.add(45);
  ll.add(63);
  ll.trace();

}

trace 方法总是指向最后一个元素,在 add 方法中交换后头部丢失。

注意: 我知道这不是生产质量代码,而是了解 internals/quirks 的智能指针。所以,请避免代码质量注释。

你严重误解了共享指针。 https://en.cppreference.com/w/cpp/memory/shared_ptr/shared_ptr

您最需要的跟踪信息是 node::node 和 node::~node。跟踪实际节点何时创建和销毁将对您有所帮助。您还必须了解范围。

对你的 "add" 函数的快速评论(留给你的修复,超出了问题的范围,对我来说 post 太多了):

它正确地创建了单个项目列表。但是,如果您尝试再次添加,您会将 head 移动到一个临时对象,将 head 设置为 nullptr。然后,您在列表中循环游标,破坏可能存在的任何节点,直到不再存在为止。您刚刚将 nullptr 分配给 cursor 这一事实不是问题,因为您会立即抛出它可能具有的任何值,然后创建一个包含单个项目的新列表,由 cursor 而不是 head 持有。然后您超出范围,破坏游标,因此也破坏了您刚刚添加到游标的新项目。

但最大的问题是你的跟踪功能,你用它来了解你的列表,但它并没有像你想要的那样远程做任何事情。这是最大的问题,因为你认为你基于错误的信息了解正在发生的事情。如果 trace 骗了你,那么你就无法使用它来理解 add。

这是一个跟踪函数,可以正确打印列表的当前内容,而不会破坏它:

void trace() {
    cout << "trace: ";
    shared_ptr<node> cursor = head; // SHARE, do not lose head, read the docs
    while (cursor.get()) {
        cout << cursor->data << ", ";
        cursor = cursor->next;
    }
    cout << endl;
}

我建议连续调用两次跟踪函数。如果它在打印列表时没有破坏它,那么第二次调用应该与第一次调用具有相同的输出。要修复添加,您需要对其进行简化。只需按照您应该在常规节点指针上执行的操作即可。你的大问题是使用 "swap" 将你的实际数据置于一个临时对象的唯一控制之下,这将很快完成它的工作,这会破坏你的所有数据。