代码之家  ›  专栏  ›  技术社区  ›  Timmmm

在地图中存储具有自定义删除器的唯一\u ptr

  •  26
  • Timmmm  · 技术社区  · 7 年前

    为什么这样不行?

    #include <map>
    #include <memory>
    
    void deleter(int* i) {
        delete i;
    }
    
    std::map<int, std::unique_ptr<int, decltype(&deleter)>> m;
    
    void foo(int* i) {
        m[0] = std::unique_ptr<int, decltype(&deleter)>(i, &deleter);
    }
    

    检查不可理解的编译错误 https://godbolt.org/z/Uhp9NO .

    In file included from <source>:1:
    In file included from /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/map:61:
    In file included from /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/stl_map.h:63:
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/tuple:1668:9: error: no matching constructor for initialization of 'std::unique_ptr<int, void (*)(int *)>'
            second(std::forward<_Args2>(std::get<_Indexes2>(__tuple2))...)
            ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/tuple:1655:9: note: in instantiation of function template specialization 'std::pair<const int, std::unique_ptr<int, void (*)(int *)> >::pair<int &&, 0>' requested here
          : pair(__first, __second,
            ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/ext/new_allocator.h:136:23: note: in instantiation of function template specialization 'std::pair<const int, std::unique_ptr<int, void (*)(int *)> >::pair<int &&>' requested here
            { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
                                 ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/alloc_traits.h:475:8: note: in instantiation of function template specialization '__gnu_cxx::new_allocator<std::_Rb_tree_node<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > > >::construct<std::pair<const int, std::unique_ptr<int, void (*)(int *)> >, const std::piecewise_construct_t &, std::tuple<int &&>, std::tuple<> >' requested here
            { __a.construct(__p, std::forward<_Args>(__args)...); }
                  ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/stl_tree.h:637:23: note: in instantiation of function template specialization 'std::allocator_traits<std::allocator<std::_Rb_tree_node<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > > > >::construct<std::pair<const int, std::unique_ptr<int, void (*)(int *)> >, const std::piecewise_construct_t &, std::tuple<int &&>, std::tuple<> >' requested here
                  _Alloc_traits::construct(_M_get_Node_allocator(),
                                 ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/stl_tree.h:654:4: note: in instantiation of function template specialization 'std::_Rb_tree<int, std::pair<const int, std::unique_ptr<int, void (*)(int *)> >, std::_Select1st<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > >, std::less<int>, std::allocator<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > > >::_M_construct_node<const std::piecewise_construct_t &, std::tuple<int &&>, std::tuple<> >' requested here
              _M_construct_node(__tmp, std::forward<_Args>(__args)...);
              ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/stl_tree.h:2414:19: note: in instantiation of function template specialization 'std::_Rb_tree<int, std::pair<const int, std::unique_ptr<int, void (*)(int *)> >, std::_Select1st<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > >, std::less<int>, std::allocator<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > > >::_M_create_node<const std::piecewise_construct_t &, std::tuple<int &&>, std::tuple<> >' requested here
            _Link_type __z = _M_create_node(std::forward<_Args>(__args)...);
                             ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/stl_map.h:518:15: note: in instantiation of function template specialization 'std::_Rb_tree<int, std::pair<const int, std::unique_ptr<int, void (*)(int *)> >, std::_Select1st<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > >, std::less<int>, std::allocator<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > > >::_M_emplace_hint_unique<const std::piecewise_construct_t &, std::tuple<int &&>, std::tuple<> >' requested here
              __i = _M_t._M_emplace_hint_unique(__i, std::piecewise_construct,
                         ^
    <source>:11:6: note: in instantiation of member function 'std::map<int, std::unique_ptr<int, void (*)(int *)>, std::less<int>, std::allocator<std::pair<const int, std::unique_ptr<int, void (*)(int *)> > > >::operator[]' requested here
        m[0] = std::unique_ptr<int, decltype(&deleter)>(i, &deleter);
         ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:191:12: note: candidate template ignored: substitution failure [with _Up = void (*)(int *)]: no type named 'type' in 'std::enable_if<false, void>'
            constexpr unique_ptr() noexcept
                      ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:204:2: note: candidate constructor template not viable: requires single argument '__p', but no arguments were provided
            unique_ptr(pointer __p) noexcept
            ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:236:12: note: candidate constructor template not viable: requires 1 argument, but 0 were provided
            constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() { }
                      ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:255:2: note: candidate constructor template not viable: requires single argument '__u', but no arguments were provided
            unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept
            ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:265:2: note: candidate constructor template not viable: requires single argument '__u', but no arguments were provided
            unique_ptr(auto_ptr<_Up>&& __u) noexcept;
            ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:241:7: note: candidate constructor not viable: requires single argument '__u', but no arguments were provided
          unique_ptr(unique_ptr&& __u) noexcept
          ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:394:7: note: candidate constructor not viable: requires 1 argument, but 0 were provided
          unique_ptr(const unique_ptr&) = delete;
          ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:215:7: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
          unique_ptr(pointer __p,
          ^
    /opt/compiler-explorer/gcc-8.2.0/lib/gcc/x86_64-linux-gnu/8.2.0/../../../../include/c++/8.2.0/bits/unique_ptr.h:227:7: note: candidate constructor not viable: requires 2 arguments, but 0 were provided
          unique_ptr(pointer __p,
          ^
    1 error generated.
    Compiler returned: 1
    
    2 回复  |  直到 7 年前
        1
  •  29
  •   Maxim Egorushkin    7 年前

    问题是 m[0] 调用的默认构造函数 std::unique_ptr<int, decltype(&deleter)> ,因为它需要deleter指针,所以不可用。

    struct Deleter {
        void operator()(int* i) { delete i; }
    };
    
    std::map<int, std::unique_ptr<int, Deleter>> m;
    
    void foo(int* i) {
        m[0] = std::unique_ptr<int, Deleter>(i);
    }
    

    这也比 标准::唯一的\u ptr<int,decltype(&删除器)> deleter 在每个实例中 std::unique_ptr . 即。 sizeof(std::unique_ptr<int, Deleter>) < sizeof(std::unique_ptr<int, decltype(&deleter)>)

        2
  •  13
  •   NathanOliver    7 年前

    std::unique_ptr ,当使用像您一样的自定义deleter函数时,不是默认的可构造函数。 std::map::operator[] 要求映射的值类型是默认可构造的。这意味着你不能使用 operator [] 用这种地图。

    标准::唯一\u ptr std::is_default_constructible<Deleter>::value true Deleter