Ошибка сегментации после вызова reset на unique_ptr - PullRequest
1 голос
/ 05 июня 2019

Я получаю ошибку сегментации при вызове reset для unique_ptr:

Node* tree::left_rotate(Node* node) {
    Node* temp = node->right.get();
    node->right.reset(temp->left.get());
    temp->left.reset(node); // **Here is segmentation fault happens**
    if(node->right.get()) {
        node->right->parent = node;
    }
    temp->parent = node->parent;
    if(node->parent) {
        if(node == node->parent->left.get()) {
            node->parent->left.reset(temp);
            node->parent = node->parent->left.get();
        } else if(node == node->parent->right.get()) {
            node->parent->right.reset(temp);
            node->parent = node->parent->right.get();
        }
    }
    return temp;
}

Узел имеет следующую структуру:

class Node {
    public:
        int data;
        Node* parent;
        std::unique_ptr<Node> left;
        std::unique_ptr<Node> right;
    public:
        Node() : data(0) {          
        }
        explicit Node(int d) : data(d),
                               parent(nullptr),
                               left(nullptr),
                               right(nullptr) {}        
};

отчеты gdb:

Поток 1 получил сигнал SIGSEGV, Ошибка сегментации.0x00404ae5 в std :: unique_ptr> :: ~ unique_ptr (this = 0xfeeefefa, __in_chrg =) в C: / Program Files (x86) /mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/unique_ptr.h:273 273 if (__ptr! = nullptr)

Отчет из одного верхнего стекового фрейма:

#2  0x004047e8 in std::default_delete<Node>::operator() (this=0xfe1de4,
    __ptr=0xfeeefeee)
    at C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/unique_ptr.h:81
81              delete __ptr;

Так что здесь, кажется, двойное удаление.Как решить эту проблему?Может быть, стоит иметь временный указатель в виде shared_ptr ?

1 Ответ

1 голос
/ 05 июня 2019
Node* temp = node->right.get();

temp является необработанным указателем на правый узел узла

node->right.reset(temp->left.get());

правый узел узла сбрасывается на левый узел temp, таким образом, правый узел исходного узла (к которому идут временные точки) получаетудален.Это означает, что временный необработанный указатель теперь указывает на удаленный узел.

temp->left.reset(node); // **Here is segmentation fault happens**

Поскольку temp удаляется, разыменование его, чтобы получить левый узел, приводит к плохим вещам.

Быстрое решениеМожет быть, использовать release () вместо get () на первом месте, чтобы взять на себя ответственность за правый узел узла?

...