我有一个旧考试的代码,我想从错误中解决这个问题。每次我调用insertlast / insertfirst时,我都会为我的列表分配新的内存,这些内存似乎无法释放。我用valgrind运行它并且每次调用insertfirst / insertlast时都会获得新的泄漏。 Valgrind也抱怨我的循环,我试图释放内存。我得到这样的东西:
Invalid free() / delete / delete[] / realloc()
==4548== at 0x4C2C2BC: operator delete(void*)(in/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4548== by 0x4007D6: main (code6.cpp:67)
==4548== Address 0xffefffea0 is on thread 1's stack
以下是代码:
#include <iostream>
using namespace std;
template <class T>
struct Node {
Node() : data(T()), next(nullptr) {}
Node(T d, Node * p) : data(d), next(p) {}
T data;
Node<T> * next;
};
template <class T>
void insertlast (Node<T> * p, T data) {
if (p == nullptr) {
p = new Node<T>(data, nullptr);
} else {
while (p -> next != nullptr) {
p = p -> next;
}
p -> next = new Node<T>(data, nullptr);
}
}
template <class T>
void insertfirst (Node<T> * & p, const T & data) {
Node<T> * tmp = new Node<T>(data, p);
p = tmp;
}
template <class T>
void printNode(Node<T> *& node) {
cout << node->data << " -> ";
while (node->next != nullptr) {
node = node->next;
cout << node->data << " -> ";
}
cout << endl;
}
template <class T>
void printNode2(Node<T> & node) {
cout << node.data << " -> ";
while (node.next != nullptr) {
node = *node.next;
cout << node.data << " -> ";
}
cout << endl;
}
int main() {
Node<int> node;
Node<int> * temp = &node;
Node<int> * ref = &node;
insertlast(ref, 5);
insertfirst(ref, 3);
insertlast(ref, 6);
insertfirst(ref, 2);
//printNode(ref);
//printNode2(node);
while(ref->next != nullptr){
temp = ref->next;
delete ref;
ref = temp;
}
return 0;
}
如果你能帮助我找出代码有什么问题,那将会很酷。我的猜测是它在insertfirst中的指针引用是可疑的,但我无法弄明白。 提前谢谢!
答案 0 :(得分:2)
第一次调用insertfirst
时,您将创建一个新节点,其next
指针是来自node
的静态分配的main
对象,然后当您循环时要删除其中的节点的列表,您将尝试删除此node
对象。
如果你想在列表的头部有一个sentinel对象,你应该做的是使它的next
指针指向新节点,新节点的下一个指针应该设置为{{ 1}}。像
p->next
最后提示如何调试这些东西:在纸上画出!每次操作后,将它画在纸上,这样的问题很容易被发现。
答案 1 :(得分:0)
在insertlast
函数中,如果参数p
为NULL
,那么您的代码将泄漏Node的实例。您创建新实例并将其地址分配给p
,但是一旦离开该函数,p
就会超出范围,您不再有指向新创建的实例的指针。
我想你想在p
函数中传递对insertfirst
的引用,但忘记将&
字符放在那里。
答案 2 :(得分:0)
这两个函数的接口不一致
template <class T>
void insertlast (Node<T> * p, T data) {
if (p == nullptr) {
p = new Node<T>(data, nullptr);
} else {
while (p -> next != nullptr) {
p = p -> next;
}
p -> next = new Node<T>(data, nullptr);
}
}
template <class T>
void insertfirst (Node<T> * & p, const T & data) {
Node<T> * tmp = new Node<T>(data, p);
p = tmp;
}
在第一个函数中,参数声明为Node<T> * p, T data
,而在第二个函数中,参数声明为Node<T> * & p, const T & data
在第一个函数中,您还应通过引用传递第一个参数。否则p
是函数的局部变量,它的变化不会影响原始参数。
可以通过以下方式定义
template <class T>
void insertlast ( Node<T> * &p, const T &data )
{
if ( p == nullptr )
{
p = new Node<T>(data, nullptr);
}
else
{
Node<T> *tmp = p;
while ( tmp->next != nullptr )
{
tmp = tmp->next;
}
tmp->next = new Node<T>( data, nullptr );
}
}
此外,您必须将main中的第一个节点初始化为nullptr
Node<int> *node = nullptr;
在堆栈中定义列表的第一个节点是个坏主意。这只是一个无效的设计。