如何在没有 valgrind 错误的情况下释放列表中间已删除的节点?
How to free a deleted node in the middle of a list without valgrind errors?
这是一个小测试,可以帮助演示和检查 valgrind 的 memcheck 的输出。有人可以帮我弄清楚如何从列表中间删除和释放节点吗?如果我从删除节点部分注释掉 free(cur) 和 free(cur->lock),memcheck 会告诉我有内存泄漏,但如果我将它们保留在那里,那么我将在顶部进行无效读取循环。有办法解决这个难题吗?
TEST(UtilityGeneralUnittest, valgrindTests)
{
//declare a node type
typedef struct node{
int size;
int value;
struct node *next;
pthread_mutex_t *lock;
}node_t;
//make the head
node_t *head;
head = (node_t*)malloc(1 * sizeof(node_t));
head->size = 0;
head->next = NULL;
head->lock = (pthread_mutex_t*)malloc(1 * sizeof(pthread_mutex_t));
pthread_mutex_init(head->lock, NULL);
//create array for storing values
int array[10];
//build a list with random numbers
for (int i = 0; i < 10; i++)
{
node_t *newNode;
newNode = (node_t*)malloc(1 * sizeof(node_t));
newNode->value = rand() % 100 + 1;
newNode->next = NULL;
newNode->lock = (pthread_mutex_t*) malloc(1 * sizeof(pthread_mutex_t));
pthread_mutex_init(newNode->lock, NULL);
array[i] = newNode->value;
if (head->next == NULL)
{
head->next = newNode;
head->size++;
}
else
{
node_t *tmp = head->next;
head->next = newNode;
newNode->next = tmp;
head->size++;
}
}
// assert the list added nodes
ASSERT_EQ(10, head->size);
//sanity check; print the list
node_t *printer = head;
while(printer->next != NULL)
{
printer = printer->next;
std::cout << "value: ";
std::cout << printer->value << ", ";
}
std::cout << "\n";
// the meat and potatoes: deleting with locks.
int removeMe = array[rand() % 10];
bool verifyDel = true;
int checkVal = removeMe;
node_t *prev;
node_t *cur;
prev = head;
pthread_mutex_lock(prev->lock);
while((cur = prev->next) != NULL) //******** this is the problem
{
pthread_mutex_lock(cur->lock);
if(cur->value == removeMe)
{
prev->next = cur->next;
pthread_mutex_unlock(cur->lock);
pthread_mutex_unlock(prev->lock);
cur->next = NULL;
head->size--;
free(cur->lock); ///******** this is the problem
free(cur); ///****** this is the problem
}
pthread_mutex_unlock(prev->lock);
prev = cur;
}
//pthread_mutex_unlock(prev->lock);
//verify node has been removed
printer = head;
while(printer->next != NULL)
{
printer = printer->next;
if(printer->value == checkVal)
{
verifyDel = false;
}
std::cout << "value: ";
std::cout << printer->value << ", ";
}
std::cout << "\n";
ASSERT_TRUE(verifyDel);
//clean up: delete the list
while((printer = head) != NULL)
{
head = head->next;
free(printer->lock);
free(printer);
std::cout << "free!!!" << std::endl;
}
}
查看您的循环(简化):
while ((cur = prev->next) != NULL) //* problem
{
if (cur->value == removeMe)
{
prev->next = cur->next;
cur->next = NULL;
free(cur); //* problem
}
prev = cur;
}
问题出在赋值 prev = cur
上,但仅在对 if
块求值时出现。这已释放 cur
,因此下次循环时,cur=prev->next
引用已删除的存储。
您可以通过插入 else
来解决此问题,仅当 cur
未被删除时才分配 prev
:
while ((cur = prev->next)) {
if (cur->value == removeMe) {
prev->next = cur->next;
cur->next = NULL;
free(cur);
} else {
prev = cur;
}
}
这是一个小测试,可以帮助演示和检查 valgrind 的 memcheck 的输出。有人可以帮我弄清楚如何从列表中间删除和释放节点吗?如果我从删除节点部分注释掉 free(cur) 和 free(cur->lock),memcheck 会告诉我有内存泄漏,但如果我将它们保留在那里,那么我将在顶部进行无效读取循环。有办法解决这个难题吗?
TEST(UtilityGeneralUnittest, valgrindTests)
{
//declare a node type
typedef struct node{
int size;
int value;
struct node *next;
pthread_mutex_t *lock;
}node_t;
//make the head
node_t *head;
head = (node_t*)malloc(1 * sizeof(node_t));
head->size = 0;
head->next = NULL;
head->lock = (pthread_mutex_t*)malloc(1 * sizeof(pthread_mutex_t));
pthread_mutex_init(head->lock, NULL);
//create array for storing values
int array[10];
//build a list with random numbers
for (int i = 0; i < 10; i++)
{
node_t *newNode;
newNode = (node_t*)malloc(1 * sizeof(node_t));
newNode->value = rand() % 100 + 1;
newNode->next = NULL;
newNode->lock = (pthread_mutex_t*) malloc(1 * sizeof(pthread_mutex_t));
pthread_mutex_init(newNode->lock, NULL);
array[i] = newNode->value;
if (head->next == NULL)
{
head->next = newNode;
head->size++;
}
else
{
node_t *tmp = head->next;
head->next = newNode;
newNode->next = tmp;
head->size++;
}
}
// assert the list added nodes
ASSERT_EQ(10, head->size);
//sanity check; print the list
node_t *printer = head;
while(printer->next != NULL)
{
printer = printer->next;
std::cout << "value: ";
std::cout << printer->value << ", ";
}
std::cout << "\n";
// the meat and potatoes: deleting with locks.
int removeMe = array[rand() % 10];
bool verifyDel = true;
int checkVal = removeMe;
node_t *prev;
node_t *cur;
prev = head;
pthread_mutex_lock(prev->lock);
while((cur = prev->next) != NULL) //******** this is the problem
{
pthread_mutex_lock(cur->lock);
if(cur->value == removeMe)
{
prev->next = cur->next;
pthread_mutex_unlock(cur->lock);
pthread_mutex_unlock(prev->lock);
cur->next = NULL;
head->size--;
free(cur->lock); ///******** this is the problem
free(cur); ///****** this is the problem
}
pthread_mutex_unlock(prev->lock);
prev = cur;
}
//pthread_mutex_unlock(prev->lock);
//verify node has been removed
printer = head;
while(printer->next != NULL)
{
printer = printer->next;
if(printer->value == checkVal)
{
verifyDel = false;
}
std::cout << "value: ";
std::cout << printer->value << ", ";
}
std::cout << "\n";
ASSERT_TRUE(verifyDel);
//clean up: delete the list
while((printer = head) != NULL)
{
head = head->next;
free(printer->lock);
free(printer);
std::cout << "free!!!" << std::endl;
}
}
查看您的循环(简化):
while ((cur = prev->next) != NULL) //* problem
{
if (cur->value == removeMe)
{
prev->next = cur->next;
cur->next = NULL;
free(cur); //* problem
}
prev = cur;
}
问题出在赋值 prev = cur
上,但仅在对 if
块求值时出现。这已释放 cur
,因此下次循环时,cur=prev->next
引用已删除的存储。
您可以通过插入 else
来解决此问题,仅当 cur
未被删除时才分配 prev
:
while ((cur = prev->next)) {
if (cur->value == removeMe) {
prev->next = cur->next;
cur->next = NULL;
free(cur);
} else {
prev = cur;
}
}