我正在尝试使用智能指针(std::unique_ptr
)来创建一个单向链表。下面是一个带有原始指针的单向链表的例子。
struct Node {
int data;
Node *next = nullptr;
Node(int data) : data{data}, next{nullptr} {}
~Node() { std::cout << "Destroy node with data: " << data << '\n'; }
};
void print_list(Node *head) {
while (head != nullptr) {
cout << head->data << " --> ";
head = head->next;
}
cout << "nullptr" << std::endl;
}
void insert(Node *&head, int data) {
Node *new_node = new Node{data};
new_node->next = head;
head = new_node;
}
int main(int argc, char *argv[]) {
Node *head = nullptr;
for (int i = 0; i < 5; ++i) {
insert(head, i);
}
print_list(head);
return 0;
}
输出为:
4 --> 3 --> 2 --> 1 --> 0 --> nullptr
显然上面的代码中存在内存泄漏(没有调用析构函数)。现在我想用智能指针来实现同样的事情:
struct Node {
int data = 0;
std::unique_ptr<Node> next;
Node(int data) : data{data}, next{nullptr} {}
~Node() { std::cout << "Destroy node with data: " << data << '\n'; }
};
void print_list(std::unique_ptr<Node> head) {
while (head != nullptr) {
std::cout << head->data << " --> ";
head = std::move(head->next);
}
std::cout << "nullptr" << std::endl;
}
void insert(std::unique_ptr<Node> &&head, int data) {
std::unique_ptr<Node> new_node{std::make_unique<Node>(data)};
new_node->next = std::move(head);
head = std::move(new_node);
}
// g++ -std=c++17 -Wall 2_1.cpp && ./a.out
int main(int argc, char *argv[]) {
std::unique_ptr<Node> head{nullptr};
for (int i = 0; i < 5; ++i) {
insert(std::move(head), i);
}
print_list(std::move(head));
return 0;
}
输出为:
4 --> Destroy node with data: 4
3 --> Destroy node with data: 3
2 --> Destroy node with data: 2
1 --> Destroy node with data: 1
0 --> Destroy node with data: 0
nullptr
我们可以观察到new_node
的生命周期在insert()
返回时结束,我想知道是否可以使用智能指针实现单向链表,并保留上面的函数接口。
1条答案
按热度按时间xmakbtuz1#
首先,您的
print_list
实现存在问题(仅适用于unique_ptr
的两个版本)。对于print_list
,每次将head
分配给不同的uniq_ptr
时,实际上是在释放head
中唯一的Node
,这是不希望的。相反,在print_list
中,您应该首先创建一个指向head
的临时指针,然后只对临时指针进行迭代。现在到了你的
unique_ptr
版本,你不需要把unique_ptr
作为右值引用传递,你也可以把它作为左值引用传递。这允许您在不使用
main
中的std::move
的情况下调用它们。现在来看看定义。对于插入,你需要先用给定的值创建一个新的
Node
,然后把旧的head
赋给新节点的next
,并把新节点设为新的head
:或者,您也可以在
Node
的构造函数中再添加一个参数:现在,您可以简单地创建
new_node
,如下所示:或者直接将新节点分配给
head
:对于
print_list
,我们应该首先创建一个指向head
底层对象的临时指针,然后通过将临时指针赋给下一个对象的底层对象来迭代列表:现在,您的main将如下所示:
Demo