智能指针 - 现代C++新特性总结
C++98中的智能指针通过一个模板类auto_ptr
来实现,new
操作符返回的指针可以交由它来管理,程序员不用再显式的调用delete
,这在一定程度上避免了堆内存忘记释放的问题;不过auto_ptr
有一些缺点,比如拷贝时返回一个左值,不能调用delete[]等。
C++11中废弃了auto_ptr
,改用unique_ptr、shared_ptr、weak_ptr
等智能指针来自动回收堆分配对象,使内存管理更安全,智能指针的使用场景也变得更全面。
unique_ptr和shared_ptr
unique_ptr是唯一性智能指针,无法进行复制,但是可以移动。而shared_ptr是共享性智能指针,采用引用计数,可以拷贝和移动,移动时引用计数不会变化。
Example
#include <memory>
#include <iostream>
using namespace std;
int main()
{
unique_ptr<int> up1(new int(11));
unique_ptr<int> up2 = up1; //不能通过编译
cout << *up1 << endl; //11
unique_ptr<int> up3 = move(up1); //现在p3是数据唯一的unique_ptr智能指针
cout << *up3 << endl; //11
cout << *up1 << endl; //运行时错误
up3.reset(); //显式释放内存
up1.reset(); //不会导致运行时错误
cout << *up3 << endl; //运行时错误
shared_ptr<int> sp1(new int(22));
shared_ptr<int> sp2 = sp1;
cout << *sp1 << endl; //22
cout << *sp2 << endl; //22
sp1.reset();
cout << *sp2 << endl; //22
}
//编译选项:g++ -std=c++11 unique_share.cpp
上例中,指针调用reset成员时,智能指针都可能释放其拥有的堆内存。
从代码中可以看出,unique_ptr和shared_ptr在对所占内存的共享上还是有一定区别的。
unique_ptr不能与其他unique_ptr类型的指针共享所指对象的内存。比如unique_ptr
而shared_ptr允许多个智能指针共享地“拥有”同一堆分配对象的内存。与unique_ptr不同的是,一旦一个shared_ptr指针放弃了“所有权”,其他的shared_ptr对对象内存的引用并不会受到影响。上例中的sp2很好说明了这个状况,sp1调用了reset成员,只是使得引用计数的降低,不会导致堆内存的释放。只有在引用计数归零时,shared_ptr才会真正地释放所占有的堆内存的空间。
weak_ptr
弱智能指针,通常指向一个共享性智能指针,当要使用所指向的共享性智能指针时,使用lock方法获取,并验证共享性智能指针的有效性。
Example:
#include <memory>
#include <iostream>
using namespace std;
void Check(weak_ptr<int> &wp)
{
shared_ptr<int> sp = wp.lock(); //转换为shared_ptr<int>
if (sp != nullptr)
cout << "still " << *sp << endl;
else
cout << "pointer is invalid." << endl;
}
int main()
{
shared_ptr<int> sp1(new int(22));
shared_ptr<int> sp2 = sp1;
weak_ptr<int> wp = sp1; //指向shared_ptr<int>所指对象
cout << *sp1 << endl; //22
cout << *sp2 << endl; //22
Check(wp); //still 22
sp1.reset();
cout << *sp2 << endl; //22
Check(wp); //still 22
sp2.reset();
Check(wp); //pointer is invalid
return 0;
}
//编译选项:g++ -std=c++11 weak.cpp
上例中定义了2个shared_ptr——sp1和sp2,而weak_ptr wp同样指向该对象内存。当sp1和sp2有效时,调用wp的lock(),check会输出still 22。当分别调用sp1和sp2的reset()时,会导致堆内存对象的引用计数降为0。一旦引用计数归0,shared_ptr
整个过程中,只有shared_ptr参与了引用计数,而weak_ptr没有影响其指向的内存的引用计数。因此可以验证shared_ptr指针的有效性。
简单情况下,程序员用unique_ptr代替以前使用auto_ptr就可以使用C++11中的智能指针。而shared_ptr及weak_ptr则可用在用户需要引用计数的地方。