如何将std::shared_ptr转换为std::unique_ptr?

How to convert from std::shared_ptr to std::unique_ptr?

所以我正在尝试为二叉树构建一个模板 class。 我想用一种特殊的方式来初始化树(您可以在 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"));
}

我试过只使用 unique 而不是像那样共享:

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(),但我不知道在哪里。 感谢您的帮助!

but i somehow get error-messages all over the place. Can someone explain how to get rid of the shared_ptrs?

unique_ptr不可复制,只能移动。这意味着一旦你在 class 中放入一个 unique_ptr 成员,node 就不能再被复制:编译器为你生成的隐式复制赋值和构造函数将不会被复制还有了

所以你必须决定你希望你的class如何表现。

  • 如果你想让你的 nodes 是可复制的,你必须自己实现复制操作(你必须深度克隆树)。这将为您提供价值语义。

  • 否则,如果您不希望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) {}