Как конфертировать из std :: shared_ptr в std :: unique_ptr? - PullRequest
1 голос
/ 21 сентября 2019

Итак, я пытаюсь создать шаблонный класс для бинарных деревьев.У меня есть особый способ, которым я хочу использовать для инициализации дерева (которое вы можете увидеть в main()).

Конструктор работает с shared_ptr просто отлично, но я хочу переместить его в более легкийunique_ptr, но я как-то получаю сообщения об ошибках повсюду.Может кто-нибудь объяснить, как избавиться от shared_ptrs?Вот рабочая версия с shared_ptr:

#include <optional>
#include <memory>
#include <string>

template <class C>
class node{
private:
    C label;
    std::shared_ptr<node<C>> left;
    std::shared_ptr<node<C>> right;
public:
    node(const C& name,
            const std::optional<node<C>>& leftChild = {},
            const std::optional<node<C>>& rightChild = {}) : 
        label(name), 
        left(leftChild ? std::make_shared<node<C>>(*leftChild) : nullptr), 
        right(rightChild ? std::make_shared<node<C>>(*rightChild) : nullptr) {}
};

int main(){
    using sNode = node<std::string>;
    auto root = std::make_unique<sNode>("root", sNode("left", sNode("left.left")), sNode("right"));
}

Я пытался использовать уникальное вместо shared вот так:

template <class C>
class node{
private:
    C label;
    std::unique_ptr<node<C>> left;
    std::unique_ptr<node<C>> right;
public:
    node(const C& name,
            const std::optional<node<C>>& leftChild = {},
            const std::optional<node<C>>& rightChild = {}) : 
        label(name), 
        left(leftChild ? std::make_unique<node<C>>(*leftChild) : nullptr), 
        right(rightChild ? std::make_unique<node<C>>(*rightChild) : nullptr) {}
};

Но появляются следующие ошибки компиляции:

In file included from /usr/include/c++/7/memory:80:0,
                 from binaryTree.hpp:2,
                 from main.cpp:1:
/usr/include/c++/7/bits/unique_ptr.h: In instantiation of ‘typename std::_MakeUniq<_Tp>::__single_object std::make_unique(_Args&& ...) [with _Tp = node<std::__cxx11::basic_string<char> >; _Args = {const node<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&}; typename std::_MakeUniq<_Tp>::__single_object = std::unique_ptr<node<std::__cxx11::basic_string<char> >, std::default_delete<node<std::__cxx11::basic_string<char> > > >]’:
binaryTree.hpp:15:51:   required from ‘node<C>::node(const C&, const std::optional<node<C> >&, const std::optional<node<C> >&) [with C = std::__cxx11::basic_string<char>]’
main.cpp:7:80:   required from here
/usr/include/c++/7/bits/unique_ptr.h:825:30: error: use of deleted function ‘node<std::__cxx11::basic_string<char> >::node(const node<std::__cxx11::basic_string<char> >&)’
     { return unique_ptr<_Tp>(new _Tp(std::forward<_Args>(__args)...)); }
                              ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from main.cpp:1:0:
binaryTree.hpp:5:7: note: ‘node<std::__cxx11::basic_string<char> >::node(const node<std::__cxx11::basic_string<char> >&)’ is implicitly deleted because the default definition would be ill-formed:
 class node{
       ^~~~
binaryTree.hpp:5:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = node<std::__cxx11::basic_string<char> >; _Dp = std::default_delete<node<std::__cxx11::basic_string<char> > >]’
In file included from /usr/include/c++/7/memory:80:0,
                 from binaryTree.hpp:2,
                 from main.cpp:1:
/usr/include/c++/7/bits/unique_ptr.h:388:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~
In file included from main.cpp:1:0:
binaryTree.hpp:5:7: error: use of deleted function ‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = node<std::__cxx11::basic_string<char> >; _Dp = std::default_delete<node<std::__cxx11::basic_string<char> > >]’
 class node{
       ^~~~
In file included from /usr/include/c++/7/memory:80:0,
                 from binaryTree.hpp:2,
                 from main.cpp:1:
/usr/include/c++/7/bits/unique_ptr.h:388:7: note: declared here
       unique_ptr(const unique_ptr&) = delete;
       ^~~~~~~~~~

Полагаю, это связано с удаленным оператором присваивания для unique_ptr, и мне нужно использовать std::move() где-нибудь, но я не могу понять, где.Спасибо за вашу помощь!

1 Ответ

0 голосов
/ 21 сентября 2019

но я как-то получаю сообщения об ошибках повсюду.Может кто-нибудь объяснить, как избавиться от shared_ptrs?

unique_ptr не для копирования, только для перемещения.Это означает, что как только вы добавите в свой класс unique_ptr член, node больше не сможет быть скопирован: неявное назначение копирования и конструктор, который сгенерировал для вас компилятор, больше не будут там.

Таким образом, вы должны решить, как вы хотите, чтобы ваш класс вел себя.

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

  • В противном случае, если вы не хотите, чтобы node был копируемым, вам все равно придется выполнить глубокое клонирование объектов node вконструкторПричина в том, что, поскольку вы передаете const ссылки, вы не можете стать владельцем их памяти (и вы хотели, чтобы они const, поскольку вы, вероятно, хотели иметь возможность передавать временные данные).

  • Или вы можете изменить свой интерфейс, чтобы не получать ссылки.Вместо этого возьмите параметры приемника (т.е. по значению) и переместите их в конструктор.(@ rafix07 написал это в ответе, но теперь он удален).Вы даже можете сделать это для параметра name:

    node(C name,
            std::optional<node<C>> leftChild = {},
            std::optional<node<C>> rightChild = {}) : 
        label(std::move(name)), 
        left(leftChild ? std::make_unique<node<C>>( std::move(*leftChild) ) : nullptr), 
        right(rightChild ? std::make_unique<node<C>>( std::move(*rightChild) ) : nullptr) {}
    
...