C++智能指针 unique

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\n", sizeof(ups));
for (int i = 0; i < 10; i++)
{
  ups[i] = i;
  printf("ups[i] = %d\n", 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 objectpublic:    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};
(0)

相关推荐

  • (3条消息) C++11/14/17

    目录 环境准备 被弃用的特性 常量字符串赋值需要使用const char* 与C的兼容性 语言可用性的强化 类型推导 区间迭代 列表初始化 模板增强 面对对象增强 语言运行期的强化 Lambda表达式 ...

  • std::unique_ptr使用incomplete type的报错分析和解决

    Pimpl(Pointer to implementation)很多同学都不陌生,但是从原始指针升级到C++11的独占指针std::unique_ptr时,会遇到一个incomplete type的报 ...

  • c 11新特性之智能指针

    很多人谈到c++,说它特别难,可能有一部分就是因为c++的内存管理吧,不像java那样有虚拟机动态的管理内存,在程序运行过程中可能就会出现内存泄漏,然而这种问题其实都可以通过c++11引入的智能指针来 ...

  • unique

    unique 显示所有例句 adj. 1. 唯一的;独一无二的being the only one of its kind 2. 独特的;罕见的very special or unusual 3. ~ ...

  • 现代C一文读懂智能指针

    https://m.toutiao.com/is/JHS4MVf/ 智能指针 C++11 引入了 3 个智能指针类型: std::unique_ptr<T> :独占资源所有权的指针. st ...

  • (8条消息) C++ 智能指针 unique

    unique_ptr 是 C++ 11 提供的用于防止内存泄漏的智能指针中的一种实现,独享被管理对象指针所有权的智能指针.unique_ptr对象包装一个原始指针,并负责其生命周期.当该对象被销毁时, ...

  • Rust 智能指针(Rc)

    std::rc::Rc Rc代表引用计数 以下是标准库文档的介绍 Single-threaded reference-counting pointers. 'Rc' stands for 'Refer ...

  • 智能指针和所有权

    在编程语言中,对堆对象的内存管理是一个麻烦又复杂的问题.一不小心就会带来问题,比如JS里一直引用一个已经不使用的对象导致gc无法回收,或者C 里多个变量指向同一块内存导致重复释放.本文简单探讨一下关于 ...

  • C 11中智能指针的原理、使用、实现

    目录 理解智能指针的原理 智能指针的使用 智能指针的设计和实现 1.智能指针的作用 C 程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理.程序员自己管理堆内存可以提高了程序的 ...

  • 5000元打造全套智能家居!小米带你享受未来生活│附清单

    对于很多人来讲,智能家居的定义只停留在买个产品能连上无线网络,能用手机APP操控就可以了的阶段,比如净化器,空调之类的产品,然而实际上仅停留在这个阶段的产品,具备了智能的基本能力,但仍然还要人操作,对 ...

  • DCIB数据中心智能母线(滑轨式)

    DCIB数据中心智能母线(滑轨式)鼎圣集团  百诺网络 2020-08-21 关注 DCIB数据中心智能母线(滑轨式)  一.概述 DCIB系列智能小母线为新型母线,又叫导轨式空气绝缘型智能母线槽 ...

  • 投资584亿!我国“智能”铁路来了,全线无人驾驶还搭载北斗导航

    随着"智能产品"的普及,人们的生活是越来越好,像是智能洗衣机就可以自动定时洗衣,还有智能电视智能音箱,这些都是人类智慧的产物,最近大家有没有听过阿里巴巴新开的只能酒店呢?全程没有人 ...