c++11提供了三种智能指针:std::shared_ptr,std::unique_ptr和weak_ptr,使用时需要引用头文件< memory >
shared_ptr共享的智能指针
shared_ptr使用引用计数,每使用它一次内部引用计数加一,没析构一次,引用计数减一,减为0时释放所指向的堆内存。
初始化
可以通过以下三种方法初始化shared_ptr
构造函数
std::make_shared< T >辅助函数
class Person
{
public:
Person(int v) {
value_ = v;
}
int value_;
};
std::shared_ptr<Person> p1(new Person(1));// Person(1)的引用计数为1
std::shared_ptr<Person> p2 = std::make_shared<Person>(2);
注意,不能将一个原始指针直接赋值给一个智能指针,如下所示,因为所有的智能指针类都有一个explicit构造函数,以指针作为参数。因此不能自动将指针转换为智能指针对象,必须显式调用
std::shared_ptr<int> p4 = new int(1);// error
获取原始指针
std::shared_ptr<int> p4(new int(5));
int *pInt = p4.get();
很少用到,因为shared_ptr重载了operator*和->。
指定删除器
智能指针可以指定删除器,当智能指针的引用计数为0时,自动调用指定的删除器来释放内存。std::shared_ptr可以指定删除器的一个原因是其默认删除器不支持数组对象,这一点需要注意。
当我们用shared_ptr管理动态数组时,需要指定删除器,可以如下:
std::shared_ptr<int> p(new int[10], [](int* p){delete[] p};
也可以将std::default_delete作为删除器
std::shared_ptr<int> p(new int[10], std::default_delete<int[]>);
使用shared_ptr需注意的问题
- 不要用一个原始指针初始化多个shared_ptr
- 不要在函数实参中创建shared_ptr
- 通过shared_from_this返回this指针,得让目标类通过派生std::enable_shared_from_this< T >
class tester
{
public:
shared_ptr<tester> sget()
{
return shared_ptr<tester>(this);
}
};
int main()
{
tester t;
shared_ptr<tester> sp = t.sget(); // …
return 0;
}//导致两次释放t对象破坏堆栈
应改为:
class tester : public enable_shared_from_this<tester>
{
public:
shared_ptr<tester> sget()
{
return shared_from_this();;
}
};
- 要避免循环引用
struct AStruct;
struct BStruct;
struct AStruct {
std::shared_ptr<BStruct> bPtr;
~AStruct() { cout << "AStruct is deleted!"<<endl; }
};
struct BStruct {
std::shared_ptr<AStruct> APtr;
~BStruct() { cout << "BStruct is deleted!" << endl; }
};
void TestLoopReference()
{
std::shared_ptr<AStruct> ap(new AStruct);
std::shared_ptr<BStruct> bp(new BStruct);
ap->bPtr = bp;
bp->APtr = ap;
}//离开TestLoopReference作用域后,ap和bp的引用计数都为1,虽然他们会调用各自的析构函数,
//但是不会去delete掉new出来的原始指针。解决方法是AStruct或BStruct改为weak_ptr
- shared_ptr并不是万能的,而且使用它们的话也是需要一定的开销的
- 在多线程环境中使用共享指针时,你需要避免关于引用计数的数据竞争,shared_ptr不提供保证;详见http://blog.csdn.net/man_sion/article/details/77196766