gpt4 book ai didi

c++ - C++中学生指针节点列表中的内存泄漏

转载 作者:太空宇宙 更新时间:2023-11-04 12:48:45 25 4
gpt4 key购买 nike

我有一个节点列表,每个节点包含一个指向学生变量(这是一个类)的指针,以及一个指向下一个节点的指针。这是我的 insertAtTail 代码。

void studentRoll::insertAtTail(const Student &s) {
if (head == NULL) {
this->head = new Node;
this->head->next = NULL;
this->head->s = new Student(s);
this->tail = head;
}
else {
this->tail->next = new Node;
this->tail = this->tail->next;
this->tail->next = NULL;
this->tail->s = new Student(s);
}
}

我用valgrind调试,得到:

==11106== 16 bytes in 1 blocks are definitely lost in loss record 1 of 2
==11106== at 0x4C2D1CA: operator new(unsigned long)
(vg_replace_malloc.c:334)
==11106== by 0x402BE7: StudentRoll::insertAtTail(Student const&)
(studentRoll.cpp:15)
==11106== by 0x401CF1: main (testStudentRoll01.cpp:19)
==11106==
==11106== 16 bytes in 1 blocks are definitely lost in loss record 2 of 2
==11106== at 0x4C2D1CA: operator new(unsigned long)
(vg_replace_malloc.c:334)
==11106== by 0x402C5B: StudentRoll::insertAtTail(Student const&)
(studentRoll.cpp:22)
==11106== by 0x401E2C: main (testStudentRoll01.cpp:27)
==11106==

有人可以帮我吗?我认为存在一些问题:

this->head->s = new Student(s);

this->tail->s = new Student(s);

但我不能删除它们,因为我需要这些“学生”。并且有指向“学生”的指针。

谢谢!!

更新:这是我的析构函数

StudentRoll::~StudentRoll() {
Node *iter = head;
while (iter) {
Node *next = iter->next;
iter->s->~Student();
delete iter;
iter = next;
}
head = tail = NULL;
}

最佳答案

Can someone help me with it? I think there are some problems about:

this->head->s = new Student(s);

and

this->tail->s = new Student(s);

But I cannot delete them because I need these "Students." And there are pointers point to "Students."

这个问题可能表明您应该重新设计您的程序。在 C++ 中,您应该表达所有权语义并明确哪些对象拥有哪些资源并负责它们的清理。 C++ 中的所有权语义通过各种指针类型表示:

如果某个单个对象拥有一些堆内存,而不是直接使用原始指针和newdelete,请使用std::unique_ptr . std::unique_ptr 更好,因为它向读者传达了您的意图并使用了 RAII以帮助防止内存泄漏。

另一方面,如果对象不拥有一 block 内存,则使用引用或原始指针代替。 (在未来,C++ 标准库可能会得到一个非拥有的智能指针。)

如果您的链表数据结构拥有学生对象,它应该是释放它们的对象。在这种情况下,使用 std::unique_ptr:

void studentRoll::insertAtTail(const Student &s) {
if (head.get() == nullptr) {
this->head = std::make_unique<Node>();
this->head->next = nullptr;
this->head->s = std::make_unique<Student>(s);
this->tail = &*head; // Get a raw pointer
}
else {
this->tail->next = std::make_unique<Node>();
this->tail = &*this->tail->next; // Get a raw pointer
this->tail->next = nullptr;
this->tail->s = std::make_unique<Student>(s);
}
}

不使用 std::unique_ptr,另一种选择是简单地使 Student 成为您的 Node 类型的数据成员。但是,此决定可能表明不同的意图并具有不同的含义。例如,如果您想将 Student 对象的所有权从 Node 对象转移到其他地方,您应该使用 std::unique_ptr。如果将 Student 对象直接保留为成员,则可以通过调用 Student 的移动构造函数来实现类似的效果,但某些语义仍然不同。例如,指向 Student 的指针将失效。参见 https://stackoverflow.com/a/31724938/8887578对这两种方法进行更多比较。

如果学生对象比链表还长,那么它不应该是它们的所有者,最好使用指向此类对象的非所有者指针。在这种情况下,不要分配新的学生对象,而是从其他地方取一个指针:

void studentRoll::insertAtTail(const Student* s) {
if (head.get() == nullptr) {
this->head = std::make_unique<Node>();
this->head->next = nullptr;
this->head->s = s;
this->tail = &*head;
}
else {
this->tail->next = std::make_unique<Node>();
this->tail = &*this->tail->next;
this->tail->next = nullptr;
this->tail->s = s;
}
}

我不知道你的程序的上下文(例如,如果它是编写链表的学校练习),但在严肃的代码中,你应该使用标准库的 std::list滚动你自己的链表。然而,在许多情况下,std::vector(类似于动态增长的数组)比链表更合适。

此外,与其为 Node 提供一个无参数的默认构造函数,然后再分配其 s 成员,不如在其构造函数中将学生指针传递给它。

关于c++ - C++中学生指针节点列表中的内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50082539/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com