zoukankan      html  css  js  c++  java
  • C++智能指针 unique_ptr

    C++智能指针 unique_ptr

    unique_ptr 独占所指向的对象, 同一时刻只能有一个 unique_ptr 指向给定对象(通过禁止拷贝语义, 只有移动语义来实现), 定义于 memory (非memory.h)中, 命名空间为 std.
    标准库早期版本中定义了 auto_ptr, 它具有 unique_ptr 的部分特征, 但不是全部, 例如, 不能在容器中保存 auto_ptr, 也不能从函数中返回 auto_ptr.
    基于这些原因, 应该尽量使用 unique_ptr, 而不是 auto_ptr, 使用 unique_ptr 替换 auto_ptr.

    基本用法:

    std::unique_ptr<A> up1;
    up1.reset(new A(3));
    std::unique_ptr<A> up2(new A(4));

    A* p = up2.release();
    delete p;

    std::unique_ptr<A> up3(new A(11));
    std::unique_ptr<A> up4 = std::move(up3);
    up4 = nullptr;//显式销毁所指对象,同时智能指针变为空指针。与u_s2.reset()等价

     

    成员函数

    (1) get 获得内部对象的指针, 由于已经重载了()方法, 因此和直接使用对象是一样的.如 unique_ptr<int> sp(new int(1)); sp 与 sp.get()是等价的
    (2) release 放弃内部对象的所有权,将内部指针置为空, 返回所内部对象的指针, 此指针需要手动释放
    (3) reset 销毁内部对象并接受新的对象的所有权(如果使用缺省参数的话,也就是没有任何对象的所有权, 此时仅将内部对象释放, 并置为空)
    (4) swap 交换两个 shared_ptr 对象(即交换所拥有的对象)
    std::move(up) 所有权转移(通过移动语义), up所有权转移后,变成“空指针” (up 的定义为 std::unique_ptr<Ty> up)

    unique_ptr 不支持拷贝和赋值.
      std::unique_ptr<A> up1(new A(5));
      std::unique_ptr<A> up2(up1); // 错误, unique_ptr 不支持拷贝
      std::unique_ptr<A> up2 = up1; // 错误, unique_ptr 不支持赋值

    虽然 unique_ptr 不支持拷贝和赋值, 但是我们可以调用 release 或 reset 将指针的所有权从一个(非 const) unique_ptr 转移到另一个.
      std::unique_ptr<int> up1(new int(1));
      std::unique_ptr<int> up2(up1.release());

    虽然 unique_ptr 不支持拷贝, 但是可以从函数中返回, 甚至返回局部对象. 如下面的代码, 编译器知道要返回的对象即将被销毁, 因此执行一种特殊的"拷贝":
      template <class Ty>
      std::unique_ptr<Ty> Clone(const Ty& obj)
      {
        return std::unique_ptr<Ty>(new Ty(obj));
      }

      template <class Ty>
      std::unique_ptr<Ty> Clone(const Ty& obj)
      {
        std::unique_ptr<Ty> temp = std::unique_ptr<Ty>(new Ty(obj));
        return temp;
      }

    unique_ptr 支持管理数组

    std::unique_ptr<A[]> ups(new A[10]);
    printf("sizeof(ups) = %d ", sizeof(ups));
    for (int i = 0; i < 10; i++)
    {
      ups[i] = i;
      printf("ups[i] = %d ", ups[i]);
    }

    自定义删除器

      重载一个 unique_ptr 的删除器会影响到 unique_ptr 类型以及如何构造该类的对象, 必须在尖括号中指定删除器类型. 然后在创建或 reset 时提供删除器对象.
        unique_ptr<T, D> up;
      可以使用 decltype 来指明函数指针的类型.

                class CConnnect
                {
                    void Disconnect() { PRINT_FUN(); }
                };
    
                void Deleter(CConnnect* obj)
                {
                    obj->Disconnect(); // 做其它释放或断开连接等工作
                    delete obj; // 删除对象指针
                }
                
                std::unique_ptr<CConnnect, decltype(Deleter)*> up(new CConnnect, Deleter);

      另一种用法:

                class Deleter
                {
                public:
                    void operator() (CConnnect* obj)
                    {
                        PRINT_FUN();
                        delete obj;
                    }
                };
    
                std::unique_ptr<CConnnect, Deleter> up1(new CConnnect);
                
                std::unique_ptr<CConnnect, Deleter> up2(new CConnnect, up1.get_deleter());

    VC中的源码实现

    template<class _Ty,
    class _Dx>    // = default_delete<_Ty>
    class unique_ptr
        : public _Unique_ptr_base<_Ty, _Dx,
        tr1::is_empty<_Dx>::value
        || tr1::is_same<default_delete<_Ty>, _Dx>::value>
    {    // non-copyable pointer to an object
    public:
        typedef unique_ptr<_Ty, _Dx> _Myt;
        typedef _Unique_ptr_base<_Ty, _Dx,
            tr1::is_empty<_Dx>::value
            || tr1::is_same<default_delete<_Ty>, _Dx>::value> _Mybase;
        typedef typename _Mybase::pointer pointer;
        typedef _Ty element_type;
        typedef _Dx deleter_type;
    
        unique_ptr()
            : _Mybase(pointer(), _Dx())
        {    // default construct
            static_assert(!is_pointer<_Dx>::value,
                "unique_ptr constructed with null deleter pointer");
        }
    
    #if defined(_NATIVE_NULLPTR_SUPPORTED) 
        && !defined(_DO_NOT_USE_NULLPTR_IN_STL)
        unique_ptr(_STD nullptr_t)
            : _Mybase(pointer(), _Dx())
        {    // null pointer construct
            static_assert(!is_pointer<_Dx>::value,
                "unique_ptr constructed with null deleter pointer");
        }
    
        _Myt& operator=(_STD nullptr_t)
        {    // assign a null pointer
            reset();
            return (*this);
        }
    #endif /* defined(_NATIVE_NULLPTR_SUPPORTED) etc. */
    
        explicit unique_ptr(pointer _Ptr)
            : _Mybase(_Ptr, _Dx())
        {    // construct with pointer
            static_assert(!is_pointer<_Dx>::value,
                "unique_ptr constructed with null deleter pointer");
        }
    
        unique_ptr(pointer _Ptr,
            typename _If<tr1::is_reference<_Dx>::value, _Dx,
            const typename tr1::remove_reference<_Dx>::type&>::_Type _Dt)
            : _Mybase(_Ptr, _Dt)
        {    // construct with pointer and (maybe const) deleter&
        }
    
        unique_ptr(pointer _Ptr, typename tr1::remove_reference<_Dx>::type&& _Dt)
            : _Mybase(_Ptr, _STD move(_Dt))
        {    // construct by moving deleter
            //        static_assert(!tr1::is_reference<_Dx>::value,
            //            "unique_ptr constructed with reference to rvalue deleter");
        }
    
        unique_ptr(unique_ptr&& _Right)
            : _Mybase(_Right.release(),
            _STD forward<_Dx>(_Right.get_deleter()))
        {    // construct by moving _Right
        }
    
        template<class _Ty2,
        class _Dx2>
            unique_ptr(unique_ptr<_Ty2, _Dx2>&& _Right)
            : _Mybase(_Right.release(),
            _STD forward<_Dx2>(_Right.get_deleter()))
        {    // construct by moving _Right
        }
    
        template<class _Ty2,
        class _Dx2>
            _Myt& operator=(unique_ptr<_Ty2, _Dx2>&& _Right)
        {    // assign by moving _Right
            reset(_Right.release());
            this->get_deleter() = _STD move(_Right.get_deleter());
            return (*this);
        }
    
        _Myt& operator=(_Myt&& _Right)
        {    // assign by moving _Right
            if (this != &_Right)
            {    // different, do the move
                reset(_Right.release());
                this->get_deleter() = _STD move(_Right.get_deleter());
            }
            return (*this);
        }
    
        void swap(_Myt&& _Right)
        {    // swap elements
            if (this != &_Right)
            {    // different, do the swap
                _Swap_adl(this->_Myptr, _Right._Myptr);
                _Swap_adl(this->get_deleter(),
                    _Right.get_deleter());
            }
        }
    
        void swap(_Myt& _Right)
        {    // swap elements
            _Swap_adl(this->_Myptr, _Right._Myptr);
            _Swap_adl(this->get_deleter(),
                _Right.get_deleter());
        }
    
        ~unique_ptr()
        {    // destroy the object
            _Delete();
        }
    
        typename tr1::add_reference<_Ty>::type operator*() const
        {    // return reference to object
            return (*this->_Myptr);
        }
    
        pointer operator->() const
        {    // return pointer to class object
            return (&**this);
        }
    
        pointer get() const
        {    // return pointer to object
            return (this->_Myptr);
        }
    
        _OPERATOR_BOOL() const
        {    // test for non-null pointer
            return (this->_Myptr != pointer() ? _CONVERTIBLE_TO_TRUE : 0);
        }
    
        pointer release()
        {    // yield ownership of pointer
            pointer _Ans = this->_Myptr;
            this->_Myptr = pointer();
            return (_Ans);
        }
    
        void reset(pointer _Ptr = pointer())
        {    // establish new pointer
            if (_Ptr != this->_Myptr)
            {    // different pointer, delete old and reassign
                _Delete();
                this->_Myptr = _Ptr;
            }
        }
    
    private:
        void _Delete()
        {    // delete the pointer
            if (this->_Myptr != pointer())
                this->get_deleter()(this->_Myptr);
        }
    
        unique_ptr(const _Myt&);    // not defined
        template<class _Ty2,
        class _Dx2>
            unique_ptr(const unique_ptr<_Ty2, _Dx2>&);    // not defined
    
        _Myt& operator=(const _Myt&);    // not defined
        template<class _Ty2,
        class _Dx2>
            _Myt& operator=(const unique_ptr<_Ty2, _Dx2>&);    // not defined
    };
  • 相关阅读:
    markdown转HTML,目录生成
    schedule与scheduleAtFixedRate之Timer源码分析
    rocketmq刷盘过程
    rocketmq消息存储概述
    Cassandra修改集群名称
    Cassandra读写性能测试
    rocketmq--push消费过程
    rocketmq消费负载均衡--push消费为例
    go反射实例
    JUnit4参数的使用
  • 原文地址:https://www.cnblogs.com/diysoul/p/5930388.html
Copyright © 2011-2022 走看看