当前位置: 代码迷 >> 综合 >> unique_ptr 源码分析
  详细解决方案

unique_ptr 源码分析

热度:76   发布时间:2023-12-22 02:43:34.0
  1. unique_ptr

    • 简介

      • 独占

      • 实现了构造,实现了移动.

      • 不允许拷贝.

    • 实现

      • unique_ptr提供了指针拥有的接口

      • __uniq_ptr_impl提供的是数据和析构类.

  2. 源码

    • 源码

       template <typename _Tp, typename _Dp = default_delete<_Tp>>class unique_ptr{
                template <class _Up>using _DeleterConstraint =typename __uniq_ptr_impl<_Tp, _Up>::_DeleterConstraint::type;__uniq_ptr_impl<_Tp, _Dp> _M_t;public:using pointer   = typename __uniq_ptr_impl<_Tp, _Dp>::pointer;using element_type  = _Tp;using deleter_type  = _Dp;// helper template for detecting a safe conversion from another// unique_ptrtemplate<typename _Up, typename _Ep>using __safe_conversion_up = __and_<is_convertible<typename unique_ptr<_Up, _Ep>::pointer, pointer>,__not_<is_array<_Up>>,__or_<__and_<is_reference<deleter_type>,is_same<deleter_type, _Ep>>,__and_<__not_<is_reference<deleter_type>>,is_convertible<_Ep, deleter_type>>>>;// Constructors./// Default constructor, creates a unique_ptr that owns nothing.template <typename _Up = _Dp,typename = _DeleterConstraint<_Up>>constexpr unique_ptr() noexcept: _M_t(){
                 }/** Takes ownership of a pointer.** @param __p A pointer to an object of @c element_type** The deleter will be value-initialized.*/template <typename _Up = _Dp,typename = _DeleterConstraint<_Up>>explicitunique_ptr(pointer __p) noexcept: _M_t(__p){
                 }/** Takes ownership of a pointer.** @param __p A pointer to an object of @c element_type* @param __d A reference to a deleter.** The deleter will be initialized with @p __d*/unique_ptr(pointer __p,typename conditional<is_reference<deleter_type>::value,deleter_type, const deleter_type&>::type __d) noexcept: _M_t(__p, __d) {
                 }/** Takes ownership of a pointer.** @param __p A pointer to an object of @c element_type* @param __d An rvalue reference to a deleter.** The deleter will be initialized with @p std::move(__d)*/unique_ptr(pointer __p,typename remove_reference<deleter_type>::type&& __d) noexcept: _M_t(std::move(__p), std::move(__d)){
                 static_assert(!std::is_reference<deleter_type>::value,"rvalue deleter bound to reference"); }/// Creates a unique_ptr that owns nothing.template <typename _Up = _Dp,typename = _DeleterConstraint<_Up>>constexpr unique_ptr(nullptr_t) noexcept : unique_ptr() {
                 }// Move constructors./// Move constructor.unique_ptr(unique_ptr&& __u) noexcept: _M_t(__u.release(), std::forward<deleter_type>(__u.get_deleter())) {
                 }/** @brief Converting constructor from another type** Requires that the pointer owned by @p __u is convertible to the* type of pointer owned by this object, @p __u does not own an array,* and @p __u has a compatible deleter type.*/template<typename _Up, typename _Ep, typename = _Require<__safe_conversion_up<_Up, _Ep>,typename conditional<is_reference<_Dp>::value,is_same<_Ep, _Dp>,is_convertible<_Ep, _Dp>>::type>>unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept: _M_t(__u.release(), std::forward<_Ep>(__u.get_deleter())){
                 }#if _GLIBCXX_USE_DEPRECATED
      #pragma GCC diagnostic push
      #pragma GCC diagnostic ignored "-Wdeprecated-declarations"/// Converting constructor from @c auto_ptrtemplate<typename _Up, typename = _Require<is_convertible<_Up*, _Tp*>, is_same<_Dp, default_delete<_Tp>>>>unique_ptr(auto_ptr<_Up>&& __u) noexcept;
      #pragma GCC diagnostic pop
      #endif/// Destructor, invokes the deleter if the stored pointer is not null.~unique_ptr() noexcept{
                auto& __ptr = _M_t._M_ptr();if (__ptr != nullptr)get_deleter()(__ptr);__ptr = pointer();}// Assignment./** @brief Move assignment operator.** @param __u The object to transfer ownership from.** Invokes the deleter first if this object owns a pointer.*/unique_ptr&operator=(unique_ptr&& __u) noexcept{
                reset(__u.release());get_deleter() = std::forward<deleter_type>(__u.get_deleter());return *this;}/** @brief Assignment from another type.** @param __u The object to transfer ownership from, which owns a* convertible pointer to a non-array object.** Invokes the deleter first if this object owns a pointer.*/template<typename _Up, typename _Ep>typename enable_if< __and_<__safe_conversion_up<_Up, _Ep>,is_assignable<deleter_type&, _Ep&&>>::value,unique_ptr&>::typeoperator=(unique_ptr<_Up, _Ep>&& __u) noexcept{
                reset(__u.release());get_deleter() = std::forward<_Ep>(__u.get_deleter());return *this;}/// Reset the %unique_ptr to empty, invoking the deleter if necessary.unique_ptr&operator=(nullptr_t) noexcept{
                reset();return *this;}// Observers./// Dereference the stored pointer.typename add_lvalue_reference<element_type>::typeoperator*() const{
                __glibcxx_assert(get() != pointer());return *get();}/// Return the stored pointer.pointeroperator->() const noexcept{
                _GLIBCXX_DEBUG_PEDASSERT(get() != pointer());return get();}/// Return the stored pointer.pointerget() const noexcept{
                 return _M_t._M_ptr(); }/// Return a reference to the stored deleter.deleter_type&get_deleter() noexcept{
                 return _M_t._M_deleter(); }/// Return a reference to the stored deleter.const deleter_type&get_deleter() const noexcept{
                 return _M_t._M_deleter(); }/// Return @c true if the stored pointer is not null.explicit operator bool() const noexcept{
                 return get() == pointer() ? false : true; }// Modifiers./// Release ownership of any stored pointer.pointerrelease() noexcept{
                pointer __p = get();_M_t._M_ptr() = pointer();return __p;}/** @brief Replace the stored pointer.** @param __p The new pointer to store.** The deleter will be invoked if a pointer is already owned.*/voidreset(pointer __p = pointer()) noexcept{
                using std::swap;swap(_M_t._M_ptr(), __p);if (__p != pointer())get_deleter()(__p);}/// Exchange the pointer and deleter with another object.voidswap(unique_ptr& __u) noexcept{
                using std::swap;swap(_M_t, __u._M_t);}// Disable copy from lvalue.unique_ptr(const unique_ptr&) = delete;unique_ptr& operator=(const unique_ptr&) = delete;};
    • 数据封装

       template <typename _Tp, typename _Dp>class __uniq_ptr_impl{
                template <typename _Up, typename _Ep, typename = void>struct _Ptr{
                using type = _Up*;};template <typename _Up, typename _Ep>struct_Ptr<_Up, _Ep, __void_t<typename remove_reference<_Ep>::type::pointer>>{
                using type = typename remove_reference<_Ep>::type::pointer;};public:using _DeleterConstraint = enable_if<__and_<__not_<is_pointer<_Dp>>,is_default_constructible<_Dp>>::value>;using pointer = typename _Ptr<_Tp, _Dp>::type;__uniq_ptr_impl() = default;__uniq_ptr_impl(pointer __p) : _M_t() {
                 _M_ptr() = __p; }template<typename _Del>__uniq_ptr_impl(pointer __p, _Del&& __d): _M_t(__p, std::forward<_Del>(__d)) {
                 }pointer&   _M_ptr() {
                 return std::get<0>(_M_t); }pointer    _M_ptr() const {
                 return std::get<0>(_M_t); }_Dp&       _M_deleter() {
                 return std::get<1>(_M_t); }const _Dp& _M_deleter() const {
                 return std::get<1>(_M_t); }private:tuple<pointer, _Dp> _M_t;};
      • 首先是用tuple进行的数据封装.

      • tuple有个特性就是,对于空类不占内存,非空类会占用sizeof那么大的内存.

      • 具体可以看tuple源码和模板元编程.

      • 总之,数据采用并排的方式,空类不占用空间,非空类占用析构.所以非空析构对象则会占用空间.

  3. 析构

    • 默认析构

       template<typename _Tp>struct default_delete{
                /// Default constructorconstexpr default_delete() noexcept = default;/** @brief Converting constructor.** Allows conversion from a deleter for arrays of another type, @p _Up,* only if @p _Up* is convertible to @p _Tp*.*/template<typename _Up, typename = typenameenable_if<is_convertible<_Up*, _Tp*>::value>::type>default_delete(const default_delete<_Up>&) noexcept {
                 }/// Calls @c delete @p __ptrvoidoperator()(_Tp* __ptr) const{
                static_assert(!is_void<_Tp>::value,"can't delete pointer to incomplete type");static_assert(sizeof(_Tp)>0,"can't delete pointer to incomplete type");delete __ptr;}};
    • 自定义析构

      • 通过tuple组合起来.数据以成员变量的形式保存.