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); |
| with deleter (4) |
template <class U, class D> shared_ptr (U* p, D del); template <class D> shared_ptr (nullptr_t p, D 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); |
| copy (6) |
shared_ptr (const shared_ptr& x) noexcept; template <class U> shared_ptr (const shared_ptr<U>& x) noexcept; |
| copy from weak (7) |
template <class U> explicit shared_ptr (const weak_ptr<U>& x); |
| move (8) |
shared_ptr (shared_ptr&& x) noexcept; template <class U> shared_ptr (shared_ptr<U>&& x) noexcept; |
| 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); |
| aliasing (10) |
template <class U> shared_ptr (const shared_ptr<U>& x, element_type* p) noexcept; |
问题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() {}
|
| from pointer (3) |
explicit unique_ptr (pointer p) noexcept; |
| from pointer + lvalue deleter (4) |
unique_ptr (pointer p,
typename conditional<is_reference<D>::value,D,const D&> del) noexcept;
|
| from pointer + rvalue deleter (5) |
unique_ptr (pointer p,
typename remove_reference<D>::type&& del) noexcept;
|
| move (6) |
unique_ptr (unique_ptr&& x) noexcept; |
| move-cast (7) |
template <class U, class E> unique_ptr (unique_ptr<U,E>&& x) noexcept; |
| move from auto_ptr (8) |
template <class U> unique_ptr (auto_ptr<U>&& x) noexcept; |
| copy (deleted!) (9) |
unique_ptr (const unique_ptr&) = delete; |
赋值运算符重载
| 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只定义了==与<。

浙公网安备 33010602011771号