代码之家  ›  专栏  ›  技术社区  ›  Chen Li

_可分配且std::unique_ptr

  •  6
  • Chen Li  · 技术社区  · 6 年前

    Here 是来自GCC的测试文件, live demo

    struct do_nothing
    {
        template <class T>
        void operator()(T*) {}
    };
    
    int
    main()
    {
        int i = 0;
        std::unique_ptr<int, do_nothing> p1(&i);
        std::unique_ptr<int> p2;
        static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, ""); // note ! here.    
    }
    

    std::is_assignable

    如果表达式 std::declval<T>() = std::declval<U>() 在未计算的上下文中格式良好,提供的成员常量值等于true。否则,值为假。访问检查的执行方式就像来自与这两种类型无关的上下文一样。

    std::declval :

    template<class T>
    typename std::add_rvalue_reference<T>::type declval() noexcept;
    

    返回类型为 T&& 除非 T 是(可能是符合cv的)void,在这种情况下返回类型是t。

    让我们来看一看 MoveAssignOnly :

    struct MoveAssignOnly {
      MoveAssignOnly &operator=(MoveAssignOnly &) = delete;
      MoveAssignOnly &operator=(MoveAssignOnly &&) = default;
    };
    
    int main()
    {
        static_assert(
        not std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value, "");
    }
    

    live demo :

    error: static_assert failed due to requirement '!std::is_assignable<MoveAssignOnly, MoveAssignOnly>::value'
    

    对, 它无法编译,因为它提供了一个移动分配

    让我们回到 gcc's test file std::unique_ptr . 正如我们所知, std::unique_ptr also has move assignments .

    然而,不像 struct MoveAssignOnly , static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, ""); (更清楚地说, static_assert(!std::is_assignable<std::unique_ptr<int>, std::unique_ptr<int, do_nothing>>::value, ""); 编译得很愉快。

    我一直在为libcxx实现 unique_ptr 很长一段时间,但仍然无法弄清楚:如何才能 STD::UNIQUIGYPTR 不可转让的 ( ! is_assignable STD::UNIQUIGYPTR 提供移动工作分配?

    1 回复  |  直到 6 年前
        1
  •  4
  •   Angew is no longer proud of SO    6 年前

    p1 p2 是不同类型的。不像 shared_ptr ,的删除者 unique_ptr 是指针类型的一部分。这意味着移动分配运算符不允许在两个对象之间分配(甚至移动分配) 尤尼奎 如果它们的删除程序类型不同。

    尤尼奎 还提供了分配运算符模板,该模板允许从 尤尼奎 使用不同的删除程序,但删除程序必须是可分配的(请参见 reference )。因此,可以通过使删除程序可分配来激发静态断言:

    struct do_nothing
    {
        template <class T>
        void operator()(T*) {}
    
        template <class T>
        operator std::default_delete<T>() { return {}; }
    };
    
    int
    main()
    {
        int i = 0;
        std::unique_ptr<int, do_nothing> p1(&i);
        std::unique_ptr<int> p2;
        static_assert(!std::is_assignable<decltype(p2), decltype(p1)>::value, ""); // note ! here.    
    }
    

    [Live example]