背景: 我不知道是什么促使我对此进行实验,但是我正在尝试测试内部使用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的内部/怪癖。因此,请避免使用代码质量注释。
答案 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,这将破坏您的所有数据。