为何带自定义删除器的unique_ptr移动赋值运算符被隐式删除?
带自定义删除器的std::unique_ptr移动赋值被隐式删除的原因
我定义了一个pod类型,想用带自定义删除器的std::unique_ptr传递句柄,但编译失败,提示移动赋值运算符被隐式删除。我有点困惑:我的删除器是POD类型,这类类型通常是不抛出异常的可移动赋值类型,应该符合std::unique_ptr移动赋值的要求才对?
代码示例
#include <memory_resource> #include <memory> #include <optional> #include <string_view> #include <vector> #include <cstdio> using allocator_t = std::pmr::polymorphic_allocator<std::byte>; struct pod { int a; bool b; }; template <typename T> struct allocator_delete { auto operator()(T* p) -> void { allocator_.delete_object(p); } allocator_t allocator_; }; using pod_handle_t = std::unique_ptr<pod, allocator_delete<pod>>; struct msg_outbound_metainfo_t { pod_handle_t msg_handle_; }; int main() { pod_handle_t ptr; std::vector<msg_outbound_metainfo_t> vec; auto& meta = vec.emplace_back(); meta.msg_handle_ = std::move(ptr); }
错误信息
<source>:41:37: error: use of deleted function 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(std::unique_ptr<_Tp, _Dp>&&) [with _Tp = pod; _Dp = allocator_delete<pod>]' 41 | meta.msg_handle_ = std::move(ptr); | ^ In file included from /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/memory:76, from <source>:2: /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h:406:19: note: 'std::unique_ptr<_Tp, _Dp>& std::unique_ptr<_Tp, _Dp>::operator=(std::unique_ptr<_Tp, _Dp>&&) [with _Tp = pod; _Dp = allocator_delete<pod>]' is implicitly deleted because the default definition would be ill-formed: 406 | unique_ptr& operator=(unique_ptr&&) = default; | ^~~~~~~~ /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h:406:19: error: use of deleted function 'std::__uniq_ptr_data<_Tp, _Dp, true, false>& std::__uniq_ptr_data<_Tp, _Dp, true, false>::operator=(std::__uniq_ptr_data<_Tp, _Dp, true, false>&&) [with _Tp = pod; _Dp = allocator_delete<pod>]' /opt/compiler-explorer/gcc-12.2.0/include/c++/12.2.0/bits/unique_ptr.h:243:24: note: declared here 243 | __uniq_ptr_data& operator=(__uniq_ptr_data&&) = delete; | ^~~~~~~~
问题根源与解决方案
问题本质
问题出在std::pmr::polymorphic_allocator的移动赋值特性上——它的移动赋值运算符是有条件 noexcept的,并非无条件noexcept。而std::unique_ptr的默认移动赋值运算符要求删除器的移动赋值必须是无条件noexcept的,否则编译器会隐式删除unique_ptr的移动赋值。
你的allocator_delete包含allocator_t(即polymorphic_allocator),所以它的移动赋值运算符的noexcept属性继承自polymorphic_allocator的移动赋值,也就是有条件的,不满足unique_ptr的要求。
修复方案
显式声明allocator_delete的移动赋值为无条件noexcept即可:
template <typename T> struct allocator_delete { auto operator()(T* p) -> void { allocator_.delete_object(p); } // 显式声明移动赋值为无条件noexcept allocator_delete& operator=(allocator_delete&&) noexcept = default; allocator_t allocator_; };
这样allocator_delete的移动赋值就满足了unique_ptr的要求,unique_ptr的默认移动赋值会正常生成,代码即可编译通过。
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

