参考<<Boost程序库完全开放指南>>
shared_ptr 类摘要(只列出了常用的部分)和相关说明
1 template <class T> class shared_ptr { 2 public: 3 typedef T element_type; 4 shared_ptr(); 5 template<class Y> explicit shared_ptr(Y * p); 6 template<class Y, class D> shared_ptr(Y * p); // 定制删除器 d取代简单的delete. 要求能用d()函数方式调用, d可以是函数对象或者函数指针. 7 ~shared_ptr(); 8 9 shared_ptr(shared_ptr const & r); 10 template<class Y> explicit shared_ptr(std::auto_ptr<Y> & r); 11 12 //比较运算符的比较是基于内部保存的指针.return a.get() == b.get(); 13 shared_ptr & operator = (shared_ptr const & r); 14 template<class Y> shared_ptr & operator = (shared_ptr<Y> const & r); 15 template<class Y> shared_ptr & operator = (std::auto_ptr<Y> & r); 16 17 void reset(); // 将引用计数减一,停止当前指针对原始指针的共享. 18 template<class Y> void reset(Y * p); // 引用计数减一, 同时转而共享另一个指针. 19 template<class Y, class D> void reset(Y * p, D d); 20 21 T & operator * () const; 22 T * operator -> () const; 23 T * get() const; // 获取原始指针 24 25 bool unique() const;//高效判断 26 long use_count() const; // 效率低, 建议只在调试时用. 27 28 operator unspecified_bool_type() const; // 提供隐式类型转换, 比如放在条件语句中作为bool值 29 void swap(shared_ptr & b);//交换内部指针 30 };
1. shared_ptr r 特点
- 提供 * ->操作符模仿原始指针行为, 提供隐式bool 类型转换以判断指针的有效性.
- 没有提供指针算术运算操作,除 < 运算符外. 所以可以用于标准容器.
- 可以被安全共享, 提供基本的线程安全的保证(一个 shared_ptr 可以被多个线程安全读取).
- 类型转换不能用诸如: static_cast<T*>(p.get())的形式(导致转换后指针无法再被 shared_ptr 自动管理), shared_ptr 提供类似的转型函数: static-pointer_cast<T>() , const_pointer_cast<T>() , dynamic_pointer_cast<T>() .
1 shared_ptr<std::exception> sp1 (new bad_exception("error")); 2 shared_ptr<bad_exception> sp2 = dynamic_pointer_cast<bad_exception>(sp1); 3 shared_ptr<std::exception> sp3 = static_pointer_cast<std::exception>(sp2); 4 assert(sp3 == sp1);
- 支持 << 操作符, 直接打印内部指针的值, 方便调试.
- 几乎可以100%在任何new 出现的地方接受new的动态分配结果, 然后被任意使用,完全消灭delete的使用的和内存泄露.
2. shared_ptr 的使用技巧
- 使用工厂函数 make_shared() 来包装new表达式
- shared_ptr 消除了显式delete调用, 但是 shared_ptr 构造时需要new, 导致了代码中某种不对称性.
1 #include <boostmake_shared.hpp> 2 template<class T, class ...Args> 3 shared_ptr<T> make_shared(Args && ... args);
- smart_ptr 也提供了一个 allocate_shared() 工厂函数, 比make_shared()多一个定制的内存分配器参数.
- 应用于标准容器
- 将容器作为 shared_ptr的管理对象: shared_ptr<list<T> >
- 将 shared_ptr作为容器的元素: vector<shared_ptr<T> >
- 应用于桥接模式(pimpl或者 handle/body)
- 将类的具体实现对用户隐藏,达到最小耦合, 可以不使用虚函数实现多态.
1 class sample { 2 private: 3 class impl; 4 shared_ptr<impl> p; 5 public: 6 sample(); 7 void print(); //提供给外界的接口 8 }; 9 class sample::impl { 10 public: 11 void print() { 12 cout << "impl print" << endl; 13 } 14 }; 15 sample::sample():p(new impl){} 16 void sample::print() { 17 p->print(); //调用内部类的impl 实现print. 18 } 19 sample s; 20 s.print(); //实现桥接模式
- 应用于工厂模式(前面的 make_shared() 函数也算)
1 class abstract { 2 public: 3 virtual void f() = 0; 4 virtual void g() = 0; 5 protected: 6 virtual ~abstract(){} //定义为保护的,只允许自己和子类对象调用.其他任何对象无权调用delete删除. 7 }; 8 class impl :public abstract{ 9 public: 10 virtual void f() { 11 cout << "class impl f" << endl; 12 } 13 virtual void g() { 14 cout << "class impl g" << endl; 15 } 16 }; 17 shared_ptr<abstract> create() { 18 return shared_ptr<abstract>(new impl); 19 } 20 int main(){ 21 shared_ptr<abstract> p = create(); 22 p->f(); 23 p->g(); 24 return 0; 25 } 26 /* 结果: 27 class impl f 28 class impl g 29 */
- 定制删除器
- 可以用来自动释放数据库连接, 关闭文件资源等.
1 class socket_t{}; 2 socket_t * open_socket() { 3 cout << "open socket" << endl; 4 return new socket_t; 5 } 6 void close_socket(socket_t * s) { 7 cout << "close socket" << endl; 8 } 9 int main(){ 10 socket_t * s = open_socket(); 11 shared_ptr<socket_t> p(s, close_socket); // 等价: shared_ptr<socket_t> p(s,&close_socket); 12 return 0; 13 }//离开作用域时, p为调用定制的删除器 close_socket()
- 对C语言文件操作管理就很简单了: shared_ptr<FILE> fp(fopen("./1.txt", "r"), fclose());
- shared_ptr<void>
- 优点: 能存储 void * 的指针, 而 void* 可以指向任意类型, 从而变成泛型的指针容器.
- 缺点: 丧失了原来的类型信息, 为了需要的时候正确使用, 需要用 static_pointer_cast<T> 转换. 转换会使代码不够安全, 建议不这样用.
1 /*算是删除器的高级用法了吧*/ 2 void any_func(void * p) { 3 cout << "some operate" << endl; 4 } 5 int main(){ 6 shared_ptr<void> p((void*)0, any_func); //容纳空指针,定制删除器, 实现退出作用域时调用任意函数. 7 return 0;//退出作用域时执行any_fuc() 8 } 9 /*结果 10 some operate 11 */
- 其他: 包装成员函数, 延时释放
- 以后有空再研究
weak_ptr类摘要
1 template<class T> class weak_ptr { 2 public: 3 template<class Y> weak_ptr(shared_ptr<Y> const & r); 4 weak_ptr(weak_ptr const & r); 5 ~weak_ptr(); 6 7 weak_ptr & operator = (weak_ptr const & r); 8 9 long use_count() const;//获取观测资源的引用计数 10 bool expired() const; //相当于use_count() == 0 , 但是更快 11 shared_ptr<T> lock() const; // 从被观测的share_ptr获取一个可用的shared_ptr对象, 从而操作资源 12 13 void reset(); 14 void swap(weak_ptr<T> & b); 15 };
1. weak_ptr 的特点
- 被设计为与 shared_ptr 共同工作, 可以从一个 shared_ptr 或者另一个 weak_ptr 对象构造获取资源的观测权.
- 不共享(引用)资源, 不能直接操作资源, 构造/析构不会改变观测资源的引用计数.
- 没有重载 * 和 -> , 不能像操作指针一样操作它.
2.weak_ptr 用法
- 基本用法
1 int main(){ 2 shared_ptr<int> sp(new int(10)); 3 cout << sp.use_count() << endl; 4 weak_ptr<int> wp(sp); 5 cout << wp.use_count() << endl; 6 if (!wp.expired()) { 7 shared_ptr<int> sp2 = wp.lock(); 8 *sp2 = 100; 9 cout << wp.use_count() << endl; 10 } 11 cout << wp.use_count() << endl; 12 sp.reset(); 13 cout << wp.expired() << endl; 14 cout << !wp.lock() << endl; 15 return 0; 16 } 17 /*结果 18 1 19 1 20 2 21 1 22 1 23 1 24 */
- 获得this的 shared_ptr
- weak_ptr 获取this指针的 shared_ptr , 使对象能获取shared_ptr实现自我管理. (使用lock() )
- 已经被通用实现, 在 <boost/enable_shared_from_this.hpp> 内的助手类: enable_shared_from_this<T> .
1 class self_shared :public enable_shared_from_this<self_shared> { 2 public: 3 int x; 4 self_shared(int n) :x(n) {} 5 void print() { 6 cout << "self_shared:" << x << endl; 7 } 8 }; 9 int main(){ 10 shared_ptr<self_shared> sp = make_shared<self_shared>(314); 11 sp->print(); 12 shared_ptr<self_shared> p = sp->shared_from_this(); 13 p->x = 100; 14 p->print(); 15 return 0; 16 } 17 /*结果 18 self_shared:314 19 self_shared:100 20 */
- 注意不能从一个普通对象(非shared_ptr)使用 shared_from_this() 来获取shared_ptr.
1 //语法正确, 但是会在shared_ptr析构是企图删除一个栈上分配的对象, 发生未定义行为 2 self_shared ss; 3 shared_ptr<self_shared> p = ss.shared_from_this();