2 smart Pointer(智能指针)
c++11提供两大类型的只能指针:
- class shared_ptr :共享式拥有
class unique_ptr: 独占式拥有
- 所有的智能指针被定义在头文件
<memory>
; - 智能指针只能用来管理动态内存,即new分配的动态内存;
- 所有的智能指针被定义在头文件
1 shared_ptr 指针
- 在其所指向的对象不再被需要之后,自动释放与对象相关的资源;
- shared_ptr有一个关联的计数器–引用计数,记录指向同一个对象的shared_ptr指针的数量;
- 当计数器计数为0,此对象自动释放【使用use_count()统计】;
1.1 使用shared_ptr
shared_ptr和unique_ptr公有的操作:
表达式 | 效果 |
---|---|
shared_ptr<T> sp / unique<T> up | 空智能指针,可以指向T的对象 |
p | 将p作为一个条件判断,若指向一个对象,则为true |
*p | 解引用p,获得p指向的对象 |
p->mem | 等价于(*p).mem |
p.get() | 返回p中保存的指针,要小心使用,若智能指针释放了其对象,则返回的指针是空的 |
p.swap(q ) / swap(p,q) | 交换 p,q的指针 |
shared_ptr独有的操作
表达式 | 效果 |
---|---|
make_shared<T>(args) | 返回一个shared_ptr,指向动态分配的t对象 |
shared_ptr<T>p(q) | p是shared_ptr q的拷贝,操作会递增q的计数器,q的指针必须能转换成 T* |
p =q | p和q都是shared_ptr,此操作会递减p所指向对象计数器,增加q指向对象计数器 ,如果p所指对象计数器为0,释放内存 |
p.unique() | 若p.use_count()返回1,返回true,否则false |
p.use_count() | 返回指向同一对象的智能指针的数量,速度慢,主要用于调试 |
例子:
shared_ptr<string> p(new string("hello"));
shared_ptr的接受一个指针的构造函数是explicit:
//from pointer (3)
template <class U> explicit shared_ptr (U* p);
所以不能进行隐式转换:
也可以使用make_shared()函数模板
shared_ptr<string> p(new string("hello")); //ok
shared_ptr<string> p = make_shared<string>("hello");
shared_ptr<string> p = new string("hello"); //error
shared_ptr的赋值:
- 先声明,在赋值新的指针,必须使用reset()
- 使用另一个指针拷贝
shared_ptr<string> p;
//第一种
p = new string("hello"); // error
p.reset(new string("hello")); //ok
//----------------
//第二种
shared_ptr<string> q(new string("haha"));
p = q;//两个指针指向同一个对象,计数器加一
1.2 定义 一个deleter
shared_ptr的构造函数有这么一种形式:
1. 带有两个参数,一个是指针,另一个是deleter对象,用于释放所拥有对象的Deleter对象,是一个可调用对象;
2. 在对象最后一个拥有者销毁的时候,会调用这个deleter对象;
//with deleter (4)
template <class U, class D> shared_ptr (U* p, D del);
//空指针,
template <class D> shared_ptr (nullptr_t p, D del);
例子:
shared_ptr<string> p(newstring("hello"),[](string*s){cout<<"deleter: " << *s << endl; });
cout << *p << endl;
结果为:
hello
deleter: hello
1.3 对付array
1.3.1 shared_ptr创建数组对象指针
- shared_ptr提供的默认deleter调用的是delete,不是
delete[]
- 这意味着只有shared_ptr拥有单一new对象,使用默认deleter才有效;
因此,使用shared_ptr创建一个动态数组,发生错误:
shared_ptr<int> p (new int[10]); //错误,但是能够编译
因此,
(1). 如果使用new[]一个数组对象,需要定义自己的deleter.
例如:
shared_ptr<int> p (new int[10],[](int* p){ delete[] p;});
(2).也可以使用为unique_ptr提供的辅助函数作为deleter,其内调delete[]:
shared_ptr<int> p (new int[10],default_delete<int[]>());
1.3.2 shared_ptr指针的数组类型的参数
- 在unique_ptr指针中,允许只传递对应的元素作为template实参;
- 但是shared_ptr指针不行
例如:
//int 和 int[]都可以, unique_ptr
unique_ptr<int>u1(new int[10]);
unique_ptr<int[]>u2(new int[10]);
// 只有int可以 ,shared_ptr
shared_ptr<int> p(new int[10]);
shared_ptr<int[]> p(new int[10]); //报错,不能编译
对于unique_ptr,必须明确给定第二个template实参,指出deleter:
unique_ptr<int,void(*)(int*)> u(new int[10], [](int* s){delete[] s; });
1.4 误用shared pointer
必须确保某对象只被一组shared pointer拥有,
1.4.1 shared_ptr不要与普通指针混合使用
例如:
int * p = new int;
shared_ptr<int> sp1(p);
shared_ptr<int> sp2(p);//error
这里有两组智能指针拥有所有钱,两个智能指针在销毁的时候会递减引用计数,意味着资源会被释放两次,从而p指针变成空悬指针;
所以应该创建对象的时候直接设立智能指针:
shared_ptr<int> sp1(new int);
shared_ptr<int> sp2(sp1); //ok
1.4.2 不要使用get初始化另一个智能指针或为智能指针赋值
例如:
shared_ptr<int> p(new int(42)); //引用计数为1
int * q = p.get(); //注意:使用时不能让他管理指针被释放
{//新程序块
//未定义,两个独立的共享指针指向同一个内存
shared_ptr<int>(q); //独立的,引用计数为1
}//程序结束,里面的指针引用计数为0,q被销毁
int f = *p; //错误,p的内存已被销毁
1.5 shared_ptr所有操作
shared pointer的所有操作: