本来是打算自己写的,但是看到两个写的蛮好的blog,所以嘛,偷下懒咯,正所谓迭代开发,,,哈哈哈
先贴上来源:http://blog.csdn.net/rsljdkt/article/details/12223253 和 http://blog.csdn.net/rsljdkt/article/details/12239905
//================正文开始=======================
1. 智能指针概念
智能指针是基于RAII机制实现的类(模板),具有指针的行为(重载了operator*与operator->操作符),可以“智能”地销毁其所指对象。C++11中有unique_ptr、shared_ptr与weak_ptr等智能指针,可以对动态资源进行管理
2. unique_ptr概念
unique_ptr“唯一”拥有其所指对象,同一时刻只能有一个unique_ptr指向给定对象(通过禁止拷贝语义、只有移动语义来实现)。
unique_ptr指针本身的生命周期:从unique_ptr指针创建时开始,直到离开作用域。离开作用域时,若其指向对象,则将其所指对象销毁(默认使用delete操作符,用户可指定其他操作)。
unique_ptr指针与其所指对象的关系:在智能指针生命周期内,可以改变智能指针所指对象,如创建智能指针时通过构造函数指定、通过reset方法重新指定、通过release方法释放所有权、通过移动语义转移所有权。
3. unique_ptr的基本操作:
- //智能指针的创建
- unique_ptr<int> u_i; //创建空智能指针
- u_i.reset(new int(3)); //"绑定”动态对象
- unique_ptr<int> u_i2(new int(4));//创建时指定动态对象
- //所有权的变化
- int *p_i = u_i2.release(); //释放所有权
- unique_ptr<string> u_s(new string("abc"));
- unique_ptr<string> u_s2 = std::move(u_s); //所有权转移(通过移动语义),u_s所有权转移后,变成“空指针”
- u_s2=nullptr;//显式销毁所指对象,同时智能指针变为空指针。与u_s2.reset()等价
4. unique_ptr的使用场景
(1) 动态资源的异常安全保证(利用其RAII特性):
- void foo()
- {//不安全的代码
- X *px = new X;
- // do something, exception may occurs
- delete px; // may not go here
- }
- void foo()
- {//异常安全的代码。无论是否异常发生,只要px指针成功创建,其析构函数都会被调用,确保动态资源被释放
- unique_ptr<X> px(new X);
- // do something,
- }
- unique_ptr<X> foo()
- {
- unique_ptr<X> px(new X);
- // do something
- return px; //移动语义
- }
方式一:
- vector<unique_ptr<string>> vs { new string{“Doug”}, new string{“Adams”} };
- vector<unique_ptr<string>>v;
- unique_ptr<string> p1(new string("abc"));
- v.push_back(std::move(p1));//这里需要显式的移动语义,因为unique_ptr并无copy语义
(4) 管理动态数组,因为unique_ptr有unique_ptr<X[]>重载版本,销毁动态对象时调用delete[]
- unique_ptr<int[]> p (new int[3]{1,2,3});
- p[0] = 0;// 重载了operator[]
5. 自定义资源删除操作(Deleter):
unique_ptr默认的资源删除操作是delete/delete[],若需要,可以进行自定义:
- void end_connection(connection *p) { disconnect(*p); } //资源清理函数
- unique_ptr<connection, decltype(end_connection)*> //资源清理器的“类型”
- p(&c, end_connection);// 传入函数名,会自动转换为函数指针
6 auto_ptr与unique_ptr
在C++11环境下,auto_ptr被看做“遗留的”,他们有如下区别:
auto_ptr有拷贝语义,拷贝后源对象变得无效;unique_ptr则无拷贝语义,但提供了移动语义
auto_ptr不可作为容器元素,unique_ptr可以作为容器元素
auto_ptr不可指向动态数组(尽管不会报错,但不会表现出正确行为),unique_ptr可以指向动态数组
1. shared_ptr、weak_ptr概念
- shared_ptr与weak_ptr智能指针均是C++ RAII的一种应用,可用于动态资源管理
- shared_ptr基于“引用计数”模型实现,多个shared_ptr可指向同一个动态对象,并维护了一个共享的引用计数器,记录了引用同一对象的shared_ptr实例的数量。当最后一个指向动态对象的shared_ptr销毁时,会自动销毁其所指对象(通过delete操作符)。
- shared_ptr的默认能力是管理动态内存,但支持自定义的Deleter以实现个性化的资源释放动作。
- weak_ptr用于解决“引用计数”模型循环依赖问题,weak_ptr指向一个对象,并不增减该对象的引用计数器
2. shared_ptr的基本操作
涉及到的操作无非是:shared_ptr的创建、拷贝、绑定对象的变更(reset)、shared_ptr的销毁(手动赋值为nullptr或离开作用域)、指定deleter等操作。
(1) shared_ptr的创建。可以使用两种方式:一是辅助函数make_shared(会根据传递的参数调用动态对象的构造函数);二是构造函数(可从原生指针、unique_ptr、另一个shared_ptr创建)(2) 作为条件。
- /** 通过make_shared辅助函数创建 **/
- auto s_s = make_shared<string>("hello");//动态创建string对象,调用string(const char *str)构造器,并将其“绑定”到新创建的shared_ptr实例
- shared_ptr<int> s_i; //创建指向int类型对象的”空指针“
- /** 通过构造函数构建 **/
- auto s_s2 = s_s;//拷贝构造。引用计数器加1
- int pa = new int(1);
- shared_ptr s_i2(pa); //通过原生指针构造
- unique_ptr u_i(new int(2));
- shared_ptr s_i3(u_i); //通过unique_ptr构造,u_i变成“空指针”
- string *ps = s_s.get(); //获取shared_ptr指向的动态对象的指针
若为“空智能指针”,即不指向任何对象,则为false,否则为true(3)定制资源销毁操作deleter
- shared_ptr<vector<string>> up;
- if (up) {//false
- cout << "not null" << endl;
- }
可以通过两种方式指定deleter,一是构造shared_ptr时,二是使用reset方法时
(4)重载的operator->, operator *,以及其他辅助操作如unique()、use_count(), get()等成员方法。
- void end_connection(connection *p) { disconnect(*p); }
- void f(destination &d /* other parameters */)
- {
- connection c = connect(&d);
- shared_ptr<connection> p(&c, end_connection);
- // use the connection
- // when f exits, even if by an exception, the connection will be properly closed
- }
3. weak_ptr
- weak_ptr用于配合shared_ptr使用,并不影响动态对象的生命周期,即其存在与否并不影响对象的引用计数器。
- weak_ptr并没有重载operator->和operator *操作符,因此不可直接通过weak_ptr使用对象。
- 提供了expired()与lock()成员函数,前者用于判断weak_ptr指向的对象是否已被销毁,后者返回其所指对象的shared_ptr智能指针(对象销毁时返回”空“shared_ptr)。
- 循环引用的场景:如二叉树中父节点与子节点的循环引用,容器与元素之间的循环引用等
4. shared_ptr的使用场景
- 对象之间“共享数据”,对象创建与销毁“分离”
- 放入容器中的动态对象,使用shared_ptr包装,比unique_ptr更合适
- 管理“动态数组”时,需要制定Deleter以使用delete[]操作符销毁内存,因为shared_ptr并没有针对数组的特化版本(unique_ptr有针对数组的特化版本)