介绍
shared_ptr
共享它指向的对象,多个shared_ptr可以指向(关联)相同的对象,在内部采用计数机制来实现。- 当新的shared_ptr与对象关联时,引用计数增加1。
- 当shared_ptr超出作用域时,引用计数减1。当引用计数变为0时,则表示没有任何shared_ptr与对象关联,则释放该对象。
- 为了方便后面举例,先定义AA类
class AA
{
public:
AA() { cout << "构造函数AA()" << endl; }
AA(const string& name): m_name(name) { cout << "构造函数AA(" << name << ")" << endl; }
~AA() {cout << "析构函数~AA()" << endl; }
public:
string m_name;
};
几种初始化方法
// 第一种,不推荐
AA *pa = new AA();
shared_ptr<AA> pu(pa);
// 第二种
shared_ptr<AA> pu(new AA());
// 第三种,C++14标准。
shared_ptr<AA> pu = make_shared<AA>("亚瑟");
shared_ptr
可以拷贝与赋值
AA *pa = new AA();
shared_ptr<AA> pu_1(pa);
shared_ptr<AA> pu_2 = pu_1; // 拷贝赋值
shared_ptr<AA> pu_3;
pu_3 = pu_2; // 赋值
基本使用方法
- 智能指针重载了*和->操作符,可以像使用指针一样使用
shared_ptr
。
shared_ptr<AA> pu(new AA("亚瑟"));
cout << pu->m_name << endl;
cout << (*pu).m_name << endl;
- 通过
get()
获取管理的指针
shared_ptr<AA> pu(new AA("亚瑟"));
AA* pa = pu.get();
一些需要注意的地方
- 赋值操作时,左值的shared_ptr的计数器将减1,右值shared_ptr的计算器将加1。
shared_ptr<AA> pa0(new AA("亚瑟"));
shared_ptr<AA> pa1 = pa0;
shared_ptr<AA> pa2 = pa0;
cout << "pa0.count(): " << pa0.use_count() << endl; // 3
shared_ptr<AA> pb0(new AA("李白"));
shared_ptr<AA> pb1 = pb0;
cout << "pb0.count(): " << pb0.use_count() << endl; // 2
pb1 = pa0;
cout << "pa0.count(): " << pa0.use_count() << endl; // 4,右值引用计数 +1
cout << "pb0.count(): " << pb0.use_count() << endl; // 1,左值引用计数 -1
- 用
nullptr
给shared_ptr赋值将把计数减1,如果计数为0,将释放对象,空的shared_ptr==nullptr。 - std::move()可以转移对原始指针的控制权。还可以将unique_ptr转移成shared_ptr。
void test02()
{
shared_ptr<AA> pa0(new AA("亚瑟"));
shared_ptr<AA> pa1 = pa0;
shared_ptr<AA> pa2 = pa0;
cout << "pa0.count(): " << pa0.use_count() << endl; // 3
shared_ptr<AA> pb0(new AA("李白"));
shared_ptr<AA> pb1 = pb0;
cout << "pb0.count(): " << pb0.use_count() << endl; // 2
pb0 = std::move(pa0); // pa0对象控制权力给pb0
cout << "pa0.count(): " << pa0.use_count() << endl; // 0
cout << "pb0.count(): " << pb0.use_count() << endl; // 3
}
- reset()改变与资源的关联关系。
pp.reset(); // 解除与资源的关系,资源的引用计数减1。
pp. reset(new AA("bbb")); // 解除与资源的关系,资源的引用计数减1。关联新资源。
- 和普通指针一样,具备多态性质
shared_ptr
不是绝对安全,如果程序中调用exit()退出,全局的shared_ptr可以自动释放,但局部的shared_ptr无法释放shared_ptr
提供了支持数组的具体化版本。
// shared_ptr<int[]> parr1(new int[3]); // 不指定初始值。
shared_ptr<int[]> parr1(new int[3]{ 33,22,11 }); // 指定初始值。
cout << "parr1[0]=" << parr1[0] << endl;
cout << "parr1[1]=" << parr1[1] << endl;
cout << "parr1[2]=" << parr1[2] << endl;
shared_ptr<AA[]> parr2(new AA[3]{string("西施"), string("冰冰"), string("幂幂")});
cout << "parr2[0].m_name=" << parr2[0].m_name << endl;
cout << "parr2[1].m_name=" << parr2[1].m_name << endl;
cout << "parr2[2].m_name=" << parr2[2].m_name << endl;
- 多线程读写
shared_ptr
所指向的同一个对象,不管是相同的shared_ptr对象,还是不同的shared_ptr对象,也需要加锁保护。
使用智能指针的好处
-
不用关心动态内存的释放问题,一般来讲,我们new出来的对象,都需要delete,但这样会存在很多潜在风险,使用shared_ptr能有效避免这些风险。
-
不要混合使用普通指针和智能指针
void process(shared_ptr<int> ptr)
{
}// 离开作用域,ptr被销毁,计数-1
int *x = new int(200);
process(shared_ptr<int>(x)); // 内存会被释放
int j = *x; // 错误,x是一个空悬指针
将一个临时的shared_ptr传给了process,调用结束时,临时对象被销毁,引用计数-1,变为0,所指向的内存被释放,此时x就成了空悬指针。注意:当用shared_ptr绑定了一个普通指针,我们就把内存管理的责任交给了shared_ptr,就不应该再使用普通指针来操作内存。