c++14 智能指针

shared_ptr

原型 

template <class T> class shared_ptr;

简介

引用计数型智能指针。其特点如下:

1.每个shared_ptr有两个指针:stored pointer、owned pointer。owned pointer是shared_ptr管理维护的实际指针,最终释放的就是这个指针,而stored pointer则是shared_ptr对外表现的,或者说其模拟的却是stored pointer。一般来说,这两者是相同的。

2.shared_ptr是为管理单个对象设计的,管理数组不方便。首先,shared_ptr的默认删除器是::delete,数组指针的释放需要::delete [],所以需要显式指定删除器。如:

shared_ptr<int> sp(new int[5],default_delete<int[]>()); 其次,shared_ptr没有定义[]运算符,引用数组成员时只能 sp.get()[],不方便。

3.shared_ptr几乎模拟了原生指针的所有操作,除了指针算数运算。

4.shared_ptr析构时调用其删除器的唯一条件是use_count()==1,不考虑owned pointer是否为空。

5.shared_ptr管理的对象是线程安全的,但shared_ptr自身不是线程安全的。

构造函数

default (1)
constexpr shared_ptr() noexcept;
空构造函数
from null pointer (2)
constexpr shared_ptr(nullptr_t) : shared_ptr() {}
空构造函数
from pointer (3)
template <class U> explicit shared_ptr (U* p);
管理指针p,use_count为1.既使p为空指针。
管理U类型的指针p,对外表现却是T*。即stroed pointer的类型是T*,而owned pointer的类型是U*。
with deleter (4)
template <class U, class D> shared_ptr (U* p, D del);
template <class D> shared_ptr (nullptr_t p, D del);
管理指针p,use_count为1.使用自定义的删除器del。
with allocator (5)
template <class U, class D, class Alloc> shared_ptr (U* p, D del, Alloc alloc);
template <class D, class Alloc> shared_ptr (nullptr_t p, D del, Alloc alloc);
管理指针p,use_count为1.使用自定义的删除器del,及自定义的分配器 alloc。
copy (6)
shared_ptr (const shared_ptr& x) noexcept;
template <class U> shared_ptr (const shared_ptr<U>& x) noexcept;
拷贝构造函数,stored pointer类型可不一致。owner pointer更是随便。
copy from weak (7)
template <class U> explicit shared_ptr (const weak_ptr<U>& x);
由weak_ptr生成shared_ptr。因为会抛异常,一般不使用,而要使用 weak_ptr<U>::lock()。
此函数应该是专为标准库的enable_shared_from_this设计出来的。
move (8)
shared_ptr (shared_ptr&& x) noexcept;
template <class U> shared_ptr (shared_ptr<U>&& x) noexcept;
move构造函数
move from managed (9)
template <class U> shared_ptr (auto_ptr<U>&& x);
template <class U, class D> shared_ptr (unique_ptr<U,D>&& x);
从auto_ptr或unique_ptr对象构造,要求参数必须为右值引用。即接管auto_ptr、unique_ptr管理的对象。
aliasing (10)
template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept;
stored pointer为p,owner pointer为x的owner pointer。一般用于使用一个shared_ptr管理的对象的成员的情况。

     问题1:为什么要为nullptr特别定义版本 ? 

     举例说明:template <class U> explicit shared_ptr (U* p);需要推导U的类型,而nullptr_t不是一个指针类型,编译会出错,所以需要为nullptr单独定义构造函数。template <class D> shared_ptr (nullptr_t p, D del);  template <class D, class Alloc> shared_ptr (nullptr_t p, D del, Alloc alloc);同理。  

    问题2:U的类型有什么要求?    

    要求U*可以隐式转换为T*,总的来说就两种:1.任何指针类型转为void *。 2.派生类指针转为其基类指针。    

    aliasing构造函数是个例外,对U的类型没有任何要求。

赋值运算符重载

copy (1)
shared_ptr& operator= (const shared_ptr& x) noexcept;
template <class U> shared_ptr& operator= (const shared_ptr<U>& x) noexcept;
move (2)
shared_ptr& operator= (shared_ptr&& x) noexcept;
template <class U> shared_ptr& operator= (shared_ptr<U>&& x) noexcept;
move from (3)
template <class U> shared_ptr& operator= (auto_ptr<U>&& x);
template <class U, class D> shared_ptr& operator= (unique_ptr<U,D>&& x);

      赋值运算符重载函数没什么需要特别说明的。除了一般的类型完全一致的shared_ptr可用于copy、move赋值,U*可转换为T*的shared_ptr也被用于赋值。

      auto_ptr、unique_ptr类型的右值可赋值给shared_ptr。

std::shared_ptr::reset

(1)
void reset() noexcept;
(2)
template <class U> void reset (U* p);
(3)
template <class U, class D> void reset (U* p, D del);
(4)
template <class U, class D, class Alloc> void reset (U* p, D del, Alloc alloc);

   shared_ptr不再管理已有的对象,而去管理p指向的对象,(3)可指定删除器,(4)可指定删除器与分配器。

   注意 没有定义 void reset(nullptr_t)。所以reset(nullptr)是错误的,需要使用 reset()。

std::shared_ptr::get

  element_type* get() const noexcept;

  返回stored pointer,不是owned pointer。

解引用

  element_type& operator*() const noexcept;

  相当于 *get().

  element_type* operator->() const noexcept;

  相当于 get()->

std::shared_ptr::operator bool

  explicit operator bool() const noexcept;

  用于条件表达式中,判断stored pointer是否为空,相当于 get()!=nullptr。

引用计数

  long int use_count() const noexcept;

  返回shared_ptr管理的对象的引用计数。use_count可能会很耗时,建议只在调试的时候用。

  bool unique() const noexcept;

  判断shared_ptr管理的对象的引用计数是否为1。相当于 use_count==1,但它却比use_count高效的多。

比较操作

(1)
template <class T, class U>
  bool operator== (const shared_ptr<T>& lhs, const shared_ptr<U>& rhs) noexcept;
template <class T> bool operator== (const shared_ptr<T>& lhs, nullptr_t) noexcept;
template <class T> bool operator== (nullptr_t, const shared_ptr<T>& rhs) noexcept;
(2)
template <class T> bool operator!= (const shared_ptr<T>& lhs, nullptr_t) noexcept;
template <class T> bool operator!= (nullptr_t, const shared_ptr<T>& rhs) noexcept;
(3)
template <class T, class U>
  bool operator<  (const shared_ptr<T>& lhs, const shared_ptr<U>& rhs) noexcept;
template <class T> bool operator<  (const shared_ptr<T>& lhs, nullptr_t) noexcept;
template <class T> bool operator<  (nullptr_t, const shared_ptr<T>& rhs) noexcept;
(4)
template <class T> bool operator<= (const shared_ptr<T>& lhs, nullptr_t) noexcept;
template <class T> bool operator<= (nullptr_t, const shared_ptr<T>& rhs) noexcept;
(5)
template <class T> bool operator>  (const shared_ptr<T>& lhs, nullptr_t) noexcept;
template <class T> bool operator>  (nullptr_t, const shared_ptr<T>& rhs) noexcept;
(6)
template <class T> bool operator>= (const shared_ptr<T>& lhs, nullptr_t) noexcept;
template <class T> bool operator>= (nullptr_t, const shared_ptr<T>& rhs) noexcept;

    template <class U> bool owner_before (const shared_ptr<U>& x) const;

    template <class U> bool owner_before (const weak_ptr<U>& x) const;

    注意:==、<比较的是stored pointer。要比较owned pointer,得使用 owner_before。

std::operator<<(shared_ptr)

template <class charT, class traits, class T> basic_ostream<charT,traits>& operator<< ( basic_ostream<charT,traits>& os, const shared_ptr<T>& x );

  shared_ptr可以像原生指针一样被打印到标准输出。相当于  os<<x.get();

swap操作

  void swap (shared_ptr& x) noexcept;

  template <class T> void swap (shared_ptr<T>& x, shared_ptr<T>& y) noexcept;

  一个成员函数,一个全局函数,交换两个同类型的shared_ptr。

类型转换

  template <class T, class U> shared_ptr<T> static_pointer_cast (const shared_ptr<U>& sp) noexcept;

  template <class T, class U> shared_ptr<T> dynamic_pointer_cast (const shared_ptr<U>& sp) noexcept;

  template <class T, class U> shared_ptr<T> const_pointer_cast (const shared_ptr<U>& sp) noexcept;

  static_pointer_cast模拟static_cast,要求与static_cast一致。即要求static_cast<T*>(sp.get())是合法的。

  dynamic_pointer_cast模拟dynamic_cast,要求与dynamic_cast一致。即要求dynamic_cast<T*>(sp.get())是合法的。

  const_pointer_cast模板const_cast,要求与const_cast一致。即要求const_cast<T*>(sp.get())是合法的。

获取自定义的删除器

  template <class D, class T> D* get_deleter (const shared_ptr<T>& sp) noexcept;

  这是个全局函数,而不是成员函数。编译器无法推导出D的类型,使用时需要指定D的类型。另外,这个函数只能返回自定义的删除器,如果shared_ptr使用默认的::delete删除对象,则get_deleter返回nullptr。

std::make_shared

template <class T, class... Args> shared_ptr<T> make_shared (Args&&... args);

生成shared_ptr<T>,参数为构造T的参数。make_shared隐藏了::new,使用更安全,不会有 fun( shared_ptr<T> (new T),g()) 一样的问题。

但make_shared指定不了删除器与分配器。

std::allocate_shared

template <class T, class Alloc, class... Args> shared_ptr<T> allocate_shared (const Alloc& alloc, Args&&... args);

生成shared_ptr<T>,第一个参数为分配器,其余参数为构造T的参数。allocate_shared与make_shared类似,但提供分配器。

std::enable_shared_from_this

template <class T> class enable_shared_from_this;

这是一个供继承的基类。主要用于那些想要在成员函数中返回 管理this指针的shared_ptr的类。其特点如下:

1.如果对象不是一个被shared_ptr管理的,调用shared_ptr会抛出一个bad_weak_ptr类型的异常。

2.不能在派生类构造函数中调用shared_from_this,会抛出bad_weak_ptr异常。因为在构造函数完成之后,enable_shared_from_this基类才能被正确初始化。

获得shared_ptr的函数为shared_from_this

shared_ptr <T> shared_from_this();

shared_ptr <const T> shared_from_this() const;

 

weak_ptr

原型

template <class T> class weak_ptr;

简介

weak_ptr为shared_ptr的伴随类,主要用于探知shared_ptr管理的对象的引用计数情况。其特点如下:

1.不具备解引用操作,也不能获得shared_ptr对象管理的指针,也没有定义任何模拟指针的操作,即不能被当作指针使用。

2.weak_ptr本身的创建与销毁不会引起引用计数的变化。

3.weak_ptr要么为空,要么指向一个shared_ptr管理的对象。

构造函数

default (1)
constexpr weak_ptr() noexcept;
copy (2)
weak_ptr (const weak_ptr& x) noexcept;
template <class U> weak_ptr (const weak_ptr<U>& x) noexcept;
from shared_ptr (3)
template <class U> weak_ptr (const shared_ptr<U>& x) noexcept;
move (4)
weak_ptr (weak_ptr&& x) noexcept;
template <class U> weak_ptr (weak_ptr<U>&& x) noexcept;

    weak_ptr只能由shared_ptr或一个已存在的weak_ptr构造。

赋值操作

copy (1)
weak_ptr& operator= (const weak_ptr& x) noexcept;
template <class U> weak_ptr& operator= (const weak_ptr<U>& x) noexcept;
from shared_ptr (2)
template <class U> weak_ptr& operator= (const shared_ptr<U>& x) noexcept;
move (3)
weak_ptr& operator= (weak_ptr&& x) noexcept;
template <class U> weak_ptr& operator= (weak_ptr<U>&& x) noexcept;

       weak_ptr只能被赋值为一个shared_ptr或一个weak_ptr。

std::weak_ptr::reset

  void reset() noexcept;

  不再指向任何对象。像shared_ptr一样,不能使用  reset(nullptr)。

引用计数

  long int use_count() const noexcept;

  返回weak_ptr指向的shared_ptr管理的对象的引用计数。与shared_ptr一样,use_count可能很慢,仅限调试时使用。

  bool expired() const noexcept;

  判断weak_ptr指向的shared_ptr管理的对象的引用计数是否为0,等价于 use_count()==0,但比其高效。expired返回真表明weak_ptr已经“过期”(指向的对象已经被释放)

std::weak_ptr::lock

  shared_ptr<element_type> lock() const noexcept;

  如果expired==false,则weak_ptr锁住其指向的对象(不让其释放),然后生成一个shared_ptr返回。如果expired==true,则返回一个空的shared_ptr。

swap

  void swap (weak_ptr& x) noexcept;

  template <class T> void swap (weak_ptr<T>& x, weak_ptr<T>& y) noexcept;

  一个成员函数,一个全局函数,交换两个同类型的weak_ptr对象。

std::weak_ptr::owner_before

  template <class U> bool owner_before (const weak_ptr<U>& x) const;

  template <class U> bool owner_before (const shared_ptr<U>& x) const;

  weak_ptr与weak_ptr之间,weak_ptr与shared_ptr之间比较其owned pointer。

 

 

unique_ptr

原型

non-specialized
template <class T, class D = default_delete<T>> class unique_ptr;
array specialization
template <class T, class D> class unique_ptr<T[],D>;

简介

  独占被管理的对象的指针。其特点如下:

  1.unique_ptr有数组版本,而shared_ptr没有。

  2.使用unique_ptr与使用原生指针一样高效,shared_ptr要慢一点。

  3.unique_ptr不能自定义分配器。而其删除器的类型也是在定义的时候就由第二个模板参数指定好了的,创建之后就无法更换,只能修改。shared_ptr要灵活的多。

  4.unique_ptr是否调用删除器的条件是其stored pointer不为空。

构造函数

default (1)
constexpr unique_ptr() noexcept;
默认构造函数
from null pointer (2)
constexpr unique_ptr (nullptr_t) noexcept : unique_ptr() {}
从nullptr构造,效果同默认构造函数
from pointer (3)
explicit unique_ptr (pointer p) noexcept;
从一个指针p构造,接收一个指针的管理权
from pointer + lvalue deleter (4)
unique_ptr (pointer p,
    typename conditional<is_reference<D>::value,D,const D&> del) noexcept;
接受一个指针和一个左值删除器来构造。如果D是一个引用类型,存储的就是一个引用,所以你就要确保原对象直到unique_ptr析构都存在。
from pointer + rvalue deleter (5)
unique_ptr (pointer p,
    typename remove_reference<D>::type&& del) noexcept;
接受一个指针和一个右值删除器来构造。copy或move构造一个新的删除器。
move (6)
unique_ptr (unique_ptr&& x) noexcept;
move构造函数
move-cast (7)
template <class U, class E>
  unique_ptr (unique_ptr<U,E>&& x) noexcept;
move构造函数,要求U*可隐式转化为T*。数组版本没有此构造函数。
move from auto_ptr (8)
template <class U>
  unique_ptr (auto_ptr<U>&& x) noexcept;
可由auto_ptr右值构造。数组版本没有此构造函数。
copy (deleted!) (9)
unique_ptr (const unique_ptr&) = delete;
删除了copy构造函数,保证其管理对象只能由一个unique_ptr管理。

赋值运算符重载

move assignment (1)
unique_ptr& operator= (unique_ptr&& x) noexcept;
assign null pointer (2)
unique_ptr& operator= (nullptr_t) noexcept;
type-cast assignment (3)
template <class U, class E>
  unique_ptr& operator= (unique_ptr<U,E>&& x) noexcept;
copy assignment (deleted!) (4)
unique_ptr& operator= (const unique_ptr&) = delete;

可由另一个unique_ptr类型的右值或nullptr赋值,不支持常规赋值。

std::unique_ptr::reset

void reset (pointer p = pointer()) noexcept;

解除对当前指针的管理,管理另一个指针。与shared_ptr不同,unique_ptr的reset不能重新指定删除器。

解引用

typename add_lvalue_reference<element_type>::type operator*() const;

pointer operator->() const noexcept;

以上两个只有non-specialized版本的unique_ptr才有。

element_type& operator[](size_t i) const; // only defined in array-specialization

这个只有数组版本的unique_ptr才有。

std::unique_ptr::release

pointer release() noexcept;

返回并不再管理存储的指针,不会执行删除操作。

swap

void swap (unique_ptr& x) noexcept;

template <class T, class D> void swap (unique_ptr<T,D>& x, unique_ptr<T,D>& y) noexcept;

一个成员函数,一个全局函数,交换同类型的两个unique_ptr对象。

std::unique_ptr::operator bool

explicit operator bool() const noexcept;

用于条件判断,判断unique_ptr是否为空或其管理的指针为空指针。

std::unique_ptr::get_deleter

deleter_type& get_deleter() noexcept;

const deleter_type& get_deleter() const noexcept;

unique_ptr的成员函数,返回其删除器的引用。所以是可通过get_deleter设置删除器的。

全局的get_deleter是用于shared_ptr的。

比较操作

1)
template <class T1, class D1, class T2, class D2>
  bool operator== (const unique_ptr<T1,D1>& lhs, const unique_ptr<T2,D2>& rhs);
template <class T, class D> bool operator== (const unique_ptr<T,D>& lhs, nullptr_t) noexcept;
template <class T, class D> bool operator== (nullptr_t, const unique_ptr<T,D>& rhs) noexcept;
(2)
template <class T1, class D1, class T2, class D2>
  bool operator!= (const unique_ptr<T1,D1>& lhs, const unique_ptr<T2,D2>& rhs);
template <class T, class D> bool operator!= (const unique_ptr<T,D>& lhs, nullptr_t) noexcept;
template <class T, class D> bool operator!= (nullptr_t, const unique_ptr<T,D>& rhs) noexcept;
(3)
template <class T1, class D1, class T2, class D2>
  bool operator<  (const unique_ptr<T1,D1>& lhs, const unique_ptr<T2,D2>& rhs);
template <class T, class D> bool operator<  (const unique_ptr<T,D>& lhs, nullptr_t) noexcept;
template <class T, class D> bool operator<  (nullptr_t, const unique_ptr<T,D>& rhs) noexcept;
(4)
template <class T1, class D1, class T2, class D2>
  bool operator<= (const unique_ptr<T1,D1>& lhs, const unique_ptr<T2,D2>& rhs);
template <class T, class D> bool operator<= (const unique_ptr<T,D>& lhs, nullptr_t) noexcept;
template <class T, class D> bool operator<= (nullptr_t, const unique_ptr<T,D>& rhs) noexcept;
(5)
template <class T1, class D1, class T2, class D2>
  bool operator>  (const unique_ptr<T1,D1>& lhs, const unique_ptr<T2,D2>& rhs);
template <class T, class D> bool operator>  (const unique_ptr<T,D>& lhs, nullptr_t) noexcept;
template <class T, class D> bool operator>  (nullptr_t, const unique_ptr<T,D>& rhs) noexcept;
(6)
template <class T1, class D1, class T2, class D2>
  bool operator>= (const unique_ptr<T1,D1>& lhs, const unique_ptr<T2,D2>& rhs);
template <class T, class D> bool operator>= (const unique_ptr<T,D>& lhs, nullptr_t) noexcept;
template <class T, class D> bool operator>= (nullptr_t, const unique_ptr<T,D>& rhs) noexcept;

  unique_ptr定义了两个unique_ptr之间的所有比较操作,包括==、!=、<、<=、>、>=,而shared_ptr只定义了==与<。


posted @ 2014-10-29 15:54  vsuu  阅读(967)  评论(0)    收藏  举报