智能指针---shared_ptr
1、什么是智能指针
智能指针(smart pointer) 是个特殊的类模板,重载了“->”和“*”运算符,实现了C++的自动内存回收机制
>智能指针通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数器跟踪有多少个对象的指针指向同一对象。
>在C++11中有四种智能指针,auto_ptr,shared_ptr,unique_ptr和weak_ptr。其中auto_ptr有很多不足之处,在C++11中已经建议废弃使用。都是在memory头文件中声明的。
2、对象指针
对象指针是函数内的局部变量,每次new出对象,但是函数返回时没有delete,造成的后果就是对象指针指向的堆区在函数运行完成后没有得到释放,对象也没有销毁,所以我们在使用动态内存时会出现两种问题,一是忘记释放内存,造成内存泄漏,二是指针还在使用就被释放,就会产生非法访问。
3、为什么使用智能指针
为了更加安全的只用动态内存,引入了智能指针的概念。智能指针的行为类似普通指针,区别在于智能指针赋值自动释放所指向的对象,标准库提供的两种指针的区别在于管理底层指针的方法不同,shared_ptr允许多个指针指向同一个对象,unique_ptr则“独占”所指向的对象。标准库还定义了一种名为weak_ptr的伴随类,它是一种弱引用,指向shared_ptr所管理的对象。
4、shared_ptr(共享智能指针)
shared_ptr(共享资源的智能指针)被用来表示共享的拥有权,也就是说,当两段代码都需要访问一些数据,而他们又都没有独占该数据的所有权(从某种意义上来说就是该段代码负责销毁该对象)。shared_ptr是一种计数指针。当引用计数变为0时,shared_ptr所指向的对象就会被删除。在给shared_ptr分配内存时建议使用make_shared函数,这样更安全。
只要将new运算符返回的指针p交给shared_ptr对象“托管”,就不必担心在那里写delete p语句了,可以不用delete,shared_ptr对象在消亡时会自动delete p。
>创建智能指针时必须提供额外的信息,指针可以指向的类型:
shared_ptr<T> p(new T); //T可以是任意类型
然后,就可以像使用普通指针一样使用了。
#include<iostream>
#include<memory>
using namespace std;
int main(void)
{
shared_ptr<int> p1(new int); //new一个int型指针,交给p1托管
*p1 = 10; //给p1指针赋值
cout << *p1 << endl;
return 0;
}
#include<iostream>
#include<memory>
using namespace std;
int main(void)
{
shared_ptr<int> p1(new int); //new一个int型指针,p1托管
shared_ptr<int> p2(p1); //p1赋值给p2
shared_ptr<int> p3;
p3 = p1; // p1赋值给p3
*p1 = 10; //p1内容为10
cout << *p1 << endl;
cout << *p2 << endl;
cout << *p3 << endl; //计数为3,有3个shared_ptr托管同一个地址
cout << "*****************" << endl;
int *q = p1.get(); //可通过get() 将p1指向的地址赋给q
cout << *q << endl;
cout << *p1 << endl;
cout << "*****************" << endl;
int *q1 = new int;
p1.reset(q1); //通过reset() 将q1的地址交给p1托管,p1丢掉原来的,计数减1
//p1 = q1 错,不能这样赋值
*q1 = 20;
cout << *p1 << endl;
cout << *p2 << endl;
cout << *p3 << endl; //计数为2
cout << "*****************" << endl;
p2 = p1; // 将p1 指向的新地址赋给p2,p3,计数减2
p3 = p1;
cout << *p1 << endl;
cout << *p2 << endl;
cout << *p3 << endl; // 计数为0,delete 掉最开始的地址
cout << "*****************" << endl;
cout << *q << endl; //由于最开始的地址被释放,所以q指向空
return 0;
}
#include <iostream>
#include <memory>
using namespace std;
class Demo{
public:
Demo()
{
cout << __func__ << ":" << __LINE__ << endl;
}
~Demo()
{
cout << __func__ << ":" << __LINE__ << endl;
}
public:
void prnmsg() const
{
cout << __func__ << ":" << __LINE__ << endl;
}
};
int main()
{
shared_ptr<Demo> p(new Demo);//智能指针p指向Demo对象
shared_ptr<Demo> pp(p);//智能指针pp和p指针同时指向Demo对象
p->prnmsg();
pp->prnmsg();
(*p).prnmsg();
(*pp).prnmsg();
return 0;
}
>shared_ptr和unique_ptr都支持的操作:
shared_ptr<T> sp 智能空指针
unique_ptr<T> up
p 将p用作一个条件判断,若p指向一个对象,则为true
*p 解引用,获得指向的对象
p->prnmsg() 相对于(*p).prnmsg()
p.get() 返回p中保存的指针,如果p内的指针被释放,返回的指针将为空
swap(p,q) 交换p和q中的指针p.swap(q)
>shared_ptr支持的操作:
make_shared<T> (args) 返回一个shared_ptr,指向一个动态分配的类型为T的对象,并用args初始化此对象
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() 返回与p共享对象的智能指针数量,可能会很慢,用于调试
shared_ptr<T> p(u) p从unique_ptr u那里接管了对象的所有权;将u置为空
shared_ptr<T> p(q,d) p接管内置指针q所指向对象的所有权,q必须能转换为T*类型。p将调用对象d
来代替delete
p.reset() 若p是唯一指向其对象的shared_ptr,reset会释放此对象
p.reset(q) 若传递可选的参数内置指针q,会令p指向q,否则将p置为空
p.reset(q,d) 将p置为空,若还传递了参数d,将会调用d而不是delete来释放q
>默认初始化的智能指针中保存着一个空指针。
>智能指针的使用方式和普通指针类似,解引用一个智能指针返回它指向的对象。
>编译时可能会报错,使用下面命令编译即可:
g++ *.cpp -o main -std=c++11