shared_ptr make_unique c++ unique-ptr

shared_ptr - c++ make_unique



Almacenar un unique_ptr con un borrado personalizado en un mapa (2)

El problema es que m[0] llama al constructor predeterminado de std::unique_ptr<int, decltype(&deleter)> , que no está disponible porque requiere el puntero de deleter.

Fijar:

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); }

Esto también es más eficiente que std::unique_ptr<int, decltype(&deleter)> porque no tiene que almacenar el mismo puntero para deleter cada instancia de std::unique_ptr . Por ejemplo, sizeof(std::unique_ptr<int, Deleter>) < sizeof(std::unique_ptr<int, decltype(&deleter)>) .

¿Por qué no funciona esto?

#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); }

Verifique el error de compilación incomprensible 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


std::unique_ptr , cuando se usa una función de eliminación personalizada como la que tiene, no se puede construir por defecto. std::map::operator[] requiere que el tipo de valor del mapa sea construible por defecto. Eso significa que, como tal, no puede usar el operator [] con este tipo de mapa.

Para que std::unique_ptr pueda construirse por defecto, necesita un deleter que satisfaga donde std::is_default_constructible<Deleter>::value sea true y Deleter no sea un tipo de puntero.