C ++ избегать проверки неинициализированного значения, удерживаемого двойным указателем

решаемая

Проблема в конечном итоге связана с дизайном структуры данных. Для удаления корневого элемента должен был быть указатель на новую кучу (новый), что было невозможно в первоначальном случае, когда данные содержались непосредственно в дереве. Сейчас есть node структура, содержащая все данные, с tree класс, содержащий все методы и корневой указатель.


У меня есть двойной указатель target_address инициализирован в NULL и я должен проверить, *target_address NULL позже. Между ними функция гарантирует, что *target_address указывает на неинициализированное значение, но Valgrind продолжает жаловаться, что я читаю неинициализированное значение только тогда, когда удаляю корневой элемент.

template <typename T>
int tree<T>::remove(T target) {
if (!this)  // root is empty
return EMPTY;

tree<T>** target_address = NULL;

if (tree_find(target, &target_address) == SUCCESS) {
// expect there to be something in target_address
if (*target_address == NULL) return EMPTY;  // <---- error happens

tree_delete(target_address);
return SUCCESS;
}
else return EMPTY;
}

tree_find, который работает на target_address

template <typename T>
int tree<T>::tree_find(T key, tree<T>*** target_address_handle) {
// find tree matched by key, or NULL pointer in correct location
// give tree pointer address back
tree<T>* root = this;   // <---- ensures *target_address points to valid value, maybe this is problematic?
tree<T>** target_address = &root;
while(*target_address) {
tree<T>* current = *target_address;
if(typeid(key) == typeid(current->data)) {
//  assume comparison operator exists
if(key == current->data)
break;
else if(key < current->data)
target_address = &current->left;
else
target_address = &current->right;
}
else return FAIL;
}
// if loop exited without breaking, will insert into an empty NULL position
// else loop exited by matching/breaking, will delete non-NULL tree
*target_address_handle = target_address;
return SUCCESS;
}

tree_delete, который также жалуется на неинициализированное значение; Я уверен, что он также жалуется на * target_address

void tree<T>::tree_delete(tree<T>** target_address) {
tree<T>* target = *target_address;
// first case: no left subtree, replace with right subtree (or NULL for a leaf)
if (!target->left)
*target_address = target->right;

// second case: no right subtree, replace with left subtree
else if (!target->right)
*target_address = target->left;

// third case: both subtrees, find second largest by taking rightmost left tree
else {
tree<T>** second_largest_address = &target->left;  // start at target's left tree
while ((*second_largest_address)->right)  // keep going right
second_largest_address = &((*second_largest_address)->right);
// reached the rightmost left
tree<T>* second_largest = *second_largest_address;
*target_address = second_largest;  // delete target by replacing it with second largest
// second largest guranteed to not have a right subtree, so can treat as case 2 by shifting
*second_largest_address = second_largest->left;
second_largest->left = target->left;
second_largest->right = target->right;
}
delete target;
}

Постскриптум Советы по настройке Valgrind для отображения номеров строк приветствуются, флаги компиляции = -g -Wall -Werror -std=c++11 и Вальгринд бежит под -q --track-origins=yes

Я пробовал статическое связывание -static как предложено в чужом вопросе, но это поставило еще много проблем и не решило ни одной …


Сообщения об ошибках

==25887== Conditional jump or move depends on uninitialised value(s)
==25887==    at 0x401764: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887==  Uninitialised value was created by a stack allocation
==25887==    at 0x40175A: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887==
After reading *target tree address
Before read
==25887== Use of uninitialised value of size 8
==25887==    at 0x401A75: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x40178E: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887==  Uninitialised value was created by a stack allocation
==25887==    at 0x401A46: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==
==25887== Use of uninitialised value of size 8
==25887==    at 0x401AA5: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x40178E: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887==  Uninitialised value was created by a stack allocation
==25887==    at 0x401A46: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==
==25887== Use of uninitialised value of size 8
==25887==    at 0x401AF2: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x40178E: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887==  Uninitialised value was created by a stack allocation
==25887==    at 0x401A46: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==
==25887== Invalid read of size 8
==25887==    at 0x401AF5: tree<int>::tree_delete(tree<int>**) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x40178E: tree<int>::remove(int) (in /home/johnson/Code/tree/treetest)
==25887==    by 0x4013AA: main (in /home/johnson/Code/tree/treetest)
==25887==  Address 0x801f0fc36d is not stack'd, malloc'd or (recently) free'd

0

Решение

Код как if (!this) return EMPTY; очень подозрительно Это неоперация и свидетельствует о неопределенном поведении в других местах. Неудивительно, что Valgrind сообщает о проблемах с вашим кодом.

Еще хуже, посмотрите на код внутри tree_find :

tree<T>* root = this;   // <-- ensures *target_address points to stack variable !
tree<T>** target_address = &root; // Set out pointer to stack variable

очевидно root тогда не существует tree_find возвращается. Нет сомнений, что это ошибка.

2

Другие решения


По вопросам рекламы [email protected]