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

时间:2019-02-03 14:45:22

标签: c++ list shared-ptr

背景: 我不知道是什么促使我对此进行实验,但是我正在尝试测试内部使用smartpointer的容器化链表。

这是repl链接: 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方法始终指向最后一个元素,在添加方法期间交换后头部丢失。

注意: 我知道这不是生产质量代码,而是了解smartpointer的内部/怪癖。因此,请避免使用代码质量注释。

1 个答案:

答案 0 :(得分:1)

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

您最需要的跟踪信息是node :: node和node ::〜node。跟踪实际节点的创建和销毁时间将为您提供帮助。您还必须了解范围。

快速批判您的“添加”功能(超出问题范围而遗留的修正内容,对我发布过多有害):

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

但是最大的问题是跟踪功能,您正在使用该功能来了解列表,但是它并没有像您想要的那样远程执行任何操作。这是最大的问题,因为您认为您根据错误信息了解发生了什么。如果跟踪对您不利,那么您将无法利用它来了解添加。

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

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;
}

我建议连续两次调用跟踪函数。如果它没有在打印列表时销毁该列表,则第二个调用应具有与第一个相同的输出。要修复添加,您需要简化它。只需按照常规节点指针执行的操作即可。您的大问题是使用“交换”将您的实际数据置于一个临时对象的唯一控制之下,这将迅速执行ITS JOB,这将破坏您的所有数据。