Почему моя функция bool, возвращающая true, приводит к нарушению прав чтения? - PullRequest
0 голосов
/ 18 апреля 2019

Я сейчас пишу BST с использованием unique_ptr. У меня есть логическая функция (удалить) для удаления данных, которая затем вызывает рекурсивную функцию (removeNode, которая возвращает bool), чтобы найти узел и удалить его. Однако иногда, когда функция удаления возвращает значение true, она вызывает нарушение прав на чтение в библиотеке памяти. Я не знаю достаточно о том, как return работает в функции, чтобы полностью понять, что происходит. Эта проблема не имеет никакого отношения к возвращению bool. Когда функция пытается вернуть объект «this», вызвавший функцию, происходит нарушение доступа.

Я установил точки останова, и рекурсивная функция возвращается очень хорошо. Это возвращает истину. Я поместил во все заглавные буквы строку, где происходит эта ошибка, потому что я не мог понять, как ее выделить.

Вот функция удаления, которая вызывает рекурсивную функцию

virtual bool removeNode(const T& data)
{
   if (root == nullptr) return false;
   if (data < root->data)
   {
    return removeNode(root->lhChild, root, false, data);
   }
   else if (data > root->data)
   {
    return removeNode(root->rhChild, root, true, data);
   }
   else if (data == root->data)
   {
    if (isLeaf(root))
    {
       root.reset(nullptr);
       --szTree;
       return true;
    }
    else if ((root->lhChild != nullptr) && (root->rhChild != nullptr))
    {
       std::unique_ptr<Node<T>> temp(root->lhChild.get());
       while (temp->rhChild != nullptr)
       {
          temp.reset(temp->rhChild.get());
       }
       root->data = temp->data;
       bool rtn = removeNode(root->lhChild, root, false, temp->data);
       RETURN TRUE;
    }
    else if (root->lhChild != nullptr)
    {
       root->data = root->lhChild->data;
       return removeNode(root->lhChild, root, false, root->data);
    }
    else
    {
       root->data = root->rhChild->data;
       return removeNode(root->rhChild, root, false, root->data);
    }
   }
}

Вот рекурсивная функция:

bool removeNode(std::unique_ptr<Node<T>>& n, std::unique_ptr<Node<T>>& p, bool isRh, T data)
{
   if (n == nullptr) return false;
   else if (n->data == data)
   {
    if (isLeaf(n))
    {
       n.reset(nullptr);
       if (isRh) p->rhChild.reset(nullptr);
       else p->lhChild.reset(nullptr);
       --szTree;
       return true;
    }
    else if ((n->lhChild != nullptr) && (n->rhChild != nullptr))
    {
       std::unique_ptr<Node<T>> temp(n->lhChild.get());
       while (temp->rhChild != nullptr)
       {
        temp.reset(temp->rhChild.get());
       }
       n->data = temp->data;
       return removeNode(n->lhChild, n, false, temp->data);
    }
    else if (n->lhChild != nullptr)
    {
       p->lhChild = std::move(n->lhChild);
       --szTree;
       return true;
    }
    else
    {
       p->rhChild = std::move(n->rhChild);
       --szTree;
       return true;
    }
   }
   else if (data < n->data) return removeNode(n->lhChild, n, false, data);
   else return removeNode(n->rhChild, n, true, data);
}

Если это поможет, вот где ошибка возникает в памяти

_NODISCARD pointer get() const noexcept { // return pointer to object
        return this->_Myptr();
    }

Ошибка гласит:

Exception thrown: read access violation.
std::_Unique_ptr_base<Node<std::basic_string<char,std::char_traits<char>,std::allocator<char> > >,std::default_delete<Node<std::basic_string<char,std::char_traits<char>,std::allocator<char> > > > >::_Myptr(...) returned 0xDDDDDDFD. occurred

Он должен возвращать true как обычно, но по какой-то причине возникают проблемы с возвратом объекта, вызвавшего функцию Из-за моего ограниченного знания о том, что происходит, когда функция возвращается, я даже не знаю, как решить эту проблему.

1 Ответ

4 голосов
/ 18 апреля 2019

Это потому, что деструктор одного из unique_ptr s вызывает нарушение прав доступа.

Это потому, что вы удаляете объект более одного раза. Когда unique_ptr уничтожается, он также удаляет объект, на который он указывает. Кроме того, вызов reset для unique_ptr удаляет объект, на который он ранее указывал.

Так что, когда вы делаете

while (temp->rhChild != nullptr)
{
    temp.reset(temp->rhChild.get());
}

вы фактически удаляете все эти узлы, которые все еще находятся в дереве, после того, как вы посмотрите на них. Но кроме того, unique_ptr (предположительно) в дереве все еще указывает на эти удаленные узлы. Таким образом, у вас есть проблемы с висящими указателями.

...