【发布时间】:2018-12-19 19:24:03
【问题描述】:
valgrind 收到此内存泄漏错误:
24 bytes in 1 blocks are definitely lost in loss record 1 of 11
at 0x4C2C21F: operator new(unsigned long) (vg_replace_malloc.c:334)
by 0x413E47: pjc::list::push_back(double) (list.cpp:33)
by 0x416371: ____C_A_T_C_H____T_E_S_T____4() (tests-list-01.cpp:86)
24 bytes in 1 blocks are definitely lost in loss record 2 of 11
at 0x4C2C21F: operator new(unsigned long) (vg_replace_malloc.c:334)
by 0x414047: pjc::list::push_front(double) (list.cpp:66)
by 0x4192C1: ____C_A_T_C_H____T_E_S_T____10() (tests-list-01.cpp:146)
我的.hpp 链表文件如下所示:
using std::size_t;
namespace pjc {
class list {
private:
struct node {
double val = 0;
node* prev = nullptr;
node* next = nullptr;
};
node* head = nullptr;
node* tail = nullptr;
size_t num_elements = 0;
public:
list() = default;
list(const list& rhs);
list& operator=(const list& rhs);
list(list&& rhs);
list& operator=(list&& rhs);
~list();
void push_back(double elem);
void push_front(double elem);
};
push_back()、push_front() 和链表的析构函数的定义如下:
list::list(const list &rhs) {
head = tail = nullptr;
for(node* tmp = rhs.head; tmp!=NULL; tmp=tmp->next) {
push_back(tmp->val);
}
num_elements = rhs.num_elements;
}
list::~list() {
node *T = head;
while(T != nullptr)
{
node *T2 = T;
T = T->next;
delete T2;
}
head = nullptr;
tail = nullptr;
num_elements = 0;
}
void list::push_back(double elem) {
node *n = new node;
n->val = elem;
if(tail == nullptr)
{
head = n;
tail = head;
}
else
{
tail->next = n;
n->prev = tail;
tail = n;
}
num_elements++;
}
void list::push_front(double elem) {
node *n = new node;
n->val = elem;
if(head == nullptr)
{
head = n;
tail = head;
}
else
{
head->prev = n;
n->next = head;
head = n;
}
num_elements++;
}
list &list::operator=(const list &rhs) {
list temp(rhs);
std::swap(head, temp.head);
std::swap(tail, temp.tail);
std::swap(num_elements, temp.num_elements);
return *this;
}
list::list(list &&rhs) {
head = rhs.head;
tail = rhs.tail;
num_elements = rhs.num_elements;
rhs.head = nullptr;
rhs.tail = nullptr;
rhs.num_elements = 0;
}
list &list::operator=(list &&rhs) {
this->~list(); // Destroy our current contents
std::swap(head, rhs.head);
std::swap(tail, rhs.tail);
std::swap(num_elements, rhs.num_elements);
return *this;
}
我尝试更改析构函数,但似乎没问题。我真的不知道泄漏发生在哪里。
编辑:对不起,我第一次遗漏了代码的一些重要部分。现在它应该遵循 5 的规则。
【问题讨论】:
-
引人注目的是违反了三法则。
-
IOW,您缺少复制构造函数和复制赋值运算符。而事实上,这段代码显然是使用 C++11 或更高版本的,所以你需要遵循五规则,其中包括添加移动构造函数和移动赋值运算符。
-
也许使用智能指针而不是原始指针?或者使用 std::list 而不是实现自己的双向链表?
-
掌握链表(或任何其他指针驱动的结构)的最佳方法之一是绘制图片。画出您希望列表看起来的样子。如果你发现自己画的东西不是你写的,那就是一个错误。然后按照您的代码,并尝试绘制相同的列表。如果你不能,那是一个错误,你可能知道它在哪里。
-
@Slava "现在看看你的代码 - 你做了所有 3 件事吗?不,你没有" - 实际上,确实如此。
标签: c++ memory-leaks linked-list valgrind doubly-linked-list