通常用容器保存指针比保存对象更好,保存智能指针比原生指针好。
在容器中保存指针需要复制指针而不是它所指向的对象。复制指针通常比复制对象快。
在容器中保存指针可以得到多态性。存放元素基类指针的容器也可以保存其派生类型的指针。
对指针容器的内容进行排序的速度要比对对象排序快,因为只需要移动指针,不需要移动对象。
保存智能指针要比保存原生指针安全,因为在对象不再被引用时,自由存储区的对象会被自动删除。这样就不会产生内存泄漏。不指向任何对象的指针默认为nullptr.
主要有两种类型的智能指针:unique_ptr<T>和shared_ptr<T>,其中unique_ptr<T>独占它所指向对象的所有权,而shared_ptr<T>允许多个指针指向同一对象。
(1) 初始化
shared_ptr<string> p1;
if(!p1) cout<<”p1==NULL”<<endl; //默认初始化的智能指针中保存着一个空指针
shared_ptr<string> p1(new string); //empty时属于string的成员函数
shared_ptr<int> pa=new int(1); //error:不允许以暴露裸露的指针进行赋值操作
//一般的初始化方式
shared_ptr<string> pint(new string(“normal usage!”));
cout<<*pint<<endl;
//推荐的安全的初始化方式
shared_ptr<string> pint1=make_shared<string>(“safe uage!”);
cout<<*pint1<<endl;
(2)get()函数
返回一个内置指针,指向智能指针的管理的对象。此函数设置的初衷是当我们向不能使用智能指针的代码传递一个内置指针。使用get返回指针的代码不能delete此指针。
shared_ptr<int> p1=make_shared<int>(32);
shared_ptr<int> p2(p1.get()); //错误的用法:但是p1、p2各自保留对一段内存的引用计数,其中有一个引用计数耗尽,资源也就释放了
(3)make_shared函数
最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准库函数,此函数在动态内存中分配一个对象并初始化它,返回此对象的shared_ptr。
shared_ptr<int> p3=make_shared<int>(42);
shared_ptr<string> pstr=make_shared<string>(“99999”);
auto pau=make_shared<string>(“auto”); //更简单,更常用的方式
使用make_shared用其参数来构造给定类型的对象;传递的参数必须能够与该类型的某个构造函数相匹配。
(4) shared_ptr的拷贝和赋值
当进行拷贝或者赋值操作时,每个shared_ptr都会记录有多少个其他的shared_ptr指向相同的对象
auto p=make_shared<int>(42); //p指向的对象只有p一个引用者
cout<<p.use_count()<<endl;
auto q(p); //p和q指向相同的对象,此对象有两个引用者
cout<<p.use_count()<<endl;
(5) 引用计数
可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数。无论何时我们拷贝一个shared_ptr,计数器都会递增。例如,当用一个shared_ptr去初始化另一个shared_ptr;当我们给shared_ptr赋予一个新的值或者是shared_ptr被销毁时,计数器就会递减。一旦一个shared_ptr的计数器变为0,就会自动释放自己所管理的对象
(6) 用erease节省内存
对于一块内存,shared_ptr类保证只要有任何shared_ptr对象引用它,他就不会被释放掉。由于这个特性,保证shared_ptr在不用之后不再保留就非常重要,通常这个过程能够自动执行而不需要人工干预,有一种例外就是我们将shared_ptr放在容器中。所以永远不要忘记erease不用的shared_ptr。
list<shared_ptr<string>> pstrList;
pstrList.push_back(make_shared<string>(“1111”));
pstrList.push_back(make_shared<string>(“222”));
pstrList.push_back(make_shared<string>(“333”));
pstrList.push_back(make_shared<string>(“4444”));
for(auto p:pstrList)
{
if(*p==”333”)
{
/*do something*/
}
cout<<*p<<endl;
}
//包含”333”的数据已经使用完
list<shared_ptr<string>>::iterator itr=pstrList.begin();
for(;itr!=pstrList.end();++iter)
{
if(**itr==”333”)
{
cout<<**itr<<endl;
pstrList.erase(itr);
}
}
总结shared_ptr使用的基本规范:
不使用相同的内置指针值初始化(或reset)多个智能指针
不delete get函数返回的指针
如果你使用get返回的指针,记住当最后一个对应的智能指针销毁后,你的指针就变为无效了
如果你使用智能指针管理的资源不是new分配的内存,记得传递给他一个删除器。