Это неопределенное поведение, чтобы изменить указатель, на который указывает unique_ptr? - PullRequest
0 голосов
/ 03 июля 2019

Выполнение reset () для необработанного указателя unique_ptr, полученного с помощью get (), является неопределенным поведением, это как:

   std::unique_ptr<int> thing(new int(8));
   int* other = thing.get();
   other.reset(new int(15));

Но что, если необработанный указатель unique_ptr может указывать на объект того же типа? Например, учитывая следующий код

class Node {
    public:
        std::unique_ptr<Node> previous;
        std::unique_ptr<Node> next;
        int data;        
        Node(int d) : previous(nullptr),
                      next(nullptr),   
                      data(d) {}
};

void some_function(std::unique_ptr<Node> node, Node* other_ptr) {
    Node* node_ptr = node.get();
    node_ptr->next.reset(other_ptr); // ***           
    ………………………………………………………………………………….
    ………………………………………………………………………………….
   // Some code. Please don't focus on the secondary things.
   // The main question whether it allowed to perform reset from line ****)
}

Это тоже неопределенное поведение? Если да, то почему.

ссылка на код: Код

1 Ответ

2 голосов
/ 03 июля 2019

При следующих предварительных условиях поведение some_function четко определено:

  • other_ptr должно быть выделено с помощью new и все еще быть действительным (не удаленным).
  • Право собственности на other_ptr должно быть передано 1 функции, т. Е. Ничему другому не принадлежит.
  • node не должно быть нулевым.

Однако node, как и все аргументы, является локальным для функции. Когда функция заканчивается, node уничтожается. Следовательно, указатель, которым он управляет, удаляется. Таким образом, бессмысленно изменять заостренный объект, что и делает функция.

1 Передача права собственности с использованием простого указателя является плохой идеей. Вместо этого вы должны использовать уникальный указатель для передачи права собственности.


P.S. С указателями next и previous, Node выглядит как двусвязный список. Однако это не может быть список, поскольку предыдущий узел и следующий узел не могут иметь уникальное право владения текущим узлом.

P.P.S. Node* node_ptr = node.get(); node_ptr->next.reset... можно упростить до node->next.reset.

...