STL一共给我们提供了四种智能指针:auto_ptr、unique_ptr、shared_ptr和weak_ptr,模板auto_ptr是C++98提供的解决方案,C+11已将将其摒弃。
使用注意点:
- 包含头文件 #include <memory>
- 所有的智能指针类都有一个explicit构造函数,以指针作为参数,因此不能自动将指针转换为智能指针对象,必须显式调用
- 智能指针只能应用于堆内存
string vacation("I wandered lonely as a cloud.");
shared_ptr<string> pvac(&vacation); // No,pvac过期时,程序将把delete运算符用于非堆内存,这是错误的
为什么摒弃auto_ptr?
- 当把一个auto_ptr赋给另外一个auto_ptr时,它的所有权也转移了,如果再次访问原指针,会造成野指针问题
- auto_ptr不能指向一组对象,就是说它不能和操作符new[]一起使用
- auto_ptr不能和标准容器(vector,list,map…)一起使用
unique_ptr为何优于auto_ptr?
- 当程序试图将一个 unique_ptr 赋值给另一个时,如果源 unique_ptr 是个临时右值,编译器允许这么做;否则编译器将禁止这么做。
unique_ptr<string> pu1(new string ("hello world"));
unique_ptr<string> pu2;
pu2 = pu1; // #1 not allowed
unique_ptr<string> pu3;
pu3 = unique_ptr<string>(new string ("You")); // #2 allowed
- std::move(),让你能够将一个unique_ptr赋给另一个,使用move后,原来的指针仍转让所有权变成空指针,可以对其重新赋值
unique_ptr<string> ps1, ps2;
ps1 = demo("hello");
ps2 = move(ps1);
ps1 = demo("alexia");
cout << *ps2 << *ps1 << endl;
- unique_ptr提供了创建数组对象的特殊方法,当指针离开作用域时,调用delete[]代替delete。当创建unique_ptr时,这一组对象被视作模板参数的部分。这样,程序员就不需要再提供一个指定的析构方法
unique_ptr<int[ ]> uptr( new int[5] );
share_ptr循环引用
如图所示,即使对象ptr_a和ptr_b被销毁,也就是①③两条引用会被断开,但是②④两条引用依然存在,每一个的引用计数都不为0,结果就导致其指向的内部对象无法析构,造成内存泄漏。
解决这种状况的办法就是将两个类中的一个成员变量改为weak_ptr对象,因为weak_ptr不会增加引用计数,使得引用不形成环,最后就可以正常的释放内部的对象。
对象ptr_a和ptr_b被销毁,也就是①③两条引用会被断开,此时CA对象的引用计数会减为0,对象被销毁,其内部的m_ptr_b成员变量也会被析构,导致CB对象的引用计数会减为0,对象被销毁,进而解决了引用成环的问题。
weak_ptr不支持普通指针包含的*,->操作。它并不包含资源所以也不允许程序员操作资源,如果需要使用它,需要使用expired函数来检测是否过期,因为它本身不会增加引用计数,所以它指向的对象可能在它用的时候已经被释放了,然后使用lock函数来获取其对应的shared_ptr对象,然后进行后续操作。
weak_ptr<T> w; //创建空 weak_ptr,可以指向类型为 T 的对象
weak_ptr<T> w(sp); //与 shared_ptr 指向相同的对象,shared_ptr 引用计数不变。T必须能转换为 sp 指向的类型
w=p; //p 可以是 shared_ptr 或 weak_ptr,赋值后 w 与 p 共享对象
w.reset(); //将 w 置空
w.use_count(); //返回与 w 共享对象的 shared_ptr 的数量
w.expired(); //若 w.use_count() 为 0,返回 true,否则返回 false
w.lock(); //如果 expired() 为 true,返回一个空 shared_ptr,否则返回非空 shared_ptr
void main( )
{
shared_ptr<Test> sptr( new Test );
weak_ptr<Test> wptr( sptr );
if (!wptr.expired()) //判断 weak_ptr 观察的对象是否失效
{
shared_ptr<Test> sptr2 = wptr.lock( );
}
}