std::shared_ptr
初始化
构造函数初始化:
std::shared_ptr<int> p(new int(1));
std::make_shared< T >初始化
std::shared_ptr<int> p = std::make_shared<int>(1);
注意:不能将一个原始指针直接复制给一个智能指针。
std::shared_ptr<int> p = new int(1);//编译报错
获取原始指针
可以用get方法来返回原始指针。
std::shared_ptr<int> p(new int(1));
int* ptr = p.get();
指定删除器
智能指针初始化可以指定删除器。
void DeleteIntPtr(int* p){
delete p;
}
std::shared_ptr<int> p(new int, DeleteIntPtr);
使用lambda表达式:
std::shared_ptr<int> p(new int, [](int* p){delete p};);
当使用shared_ptr管理动态数组是,需要指定删除器,因为其默认删除器不支持数组对象。
std::shared_ptr<int> p(new int[10], [](int* p){delete[] p};);
可以将std::default_delete作为删除器,其内部是通过调用delete实现的。
std::shared_ptr<int> p(new int[10], std::default_delete<int[]>);
使用shared_ptr需要注意的问题
- 不要用原始指针初始化多个shared_ptr
int* ptr=new int;
std::shared_ptr<int> p1(ptr);
std::shared_ptr<int> p2(ptr);//错误
- 不要在实参中创建shared_ptr
function(shared_ptr<int>(new int),g());//有缺陷
由于不同的编译器函数参数的计算顺序可能不同,可能先new int,然后调用g(),如果g()发生异常,shared_ptr< int >还没有创建,则int内存泄漏。正确写法应该先创建智能指针。
shared_ptr<int> p(new int());
function(p, g());
- 通过shared_from_this()返回this指针,不要将this指针作为shared_ptr返回出来,否则会导致重复析构。
struct A{
shared_ptr<A> Getself(){
return shared_ptr<S>(this);
}
};
int main(){
shared_ptr<A> sp1(new A);
shared_ptr<A> sp2=sp1->Getself();
return 0;
}
由于用同一个指针(this)构造了两个智能指针,所以会造成重复析构。
正确返回this 的shared_ptr的做法是:让目标类通过派生std::enable_shared_from_this< T >类,然后使用基类的成员函数shared_from_this()来返回。
class A:public std::enable_shared_from_this<A>{
std::shared_ptr<A> GetSelf(){
return shared_from_this();
}
};
std::shared_ptr<A> spy(new A);
std::shared_ptr<A> p=spy->GetSelf();
- 避免循环引用
循环引用会导致内存泄漏,下面是一个典型的循环引用的场景:
struct A{
std::shared_ptr<B> bptr;
~A() { cout << "A is deleted!" << endl; }
};
struct B{
std::shared_ptr<A> aptr;
~B() { cout << "B is deleted!" << endl; }
};
void TestPtr(){
std::shared_ptr<A> ap(new A);
std::shared_ptr<B> bp(new B);
ap->bptr = bp;
bp->aptr = ap;
}
循环引用导致ap和bp的引用计数都为2,离开作用域后减为1,产生内存泄漏。
std::unique_ptr
unique_ptr不允许其他智能指针共享其内部的指针。
unique_ptr<T> myPtr(new T);
unique_ptr<T> myOtherPtr=myPtr;//错误
unique_ptr<T> myOtherPtr=std::move(myPtr);//可以移动
unique_ptr可以指向一个数组:
std::unique_ptr<int []>ptr(new int10[]);
unique_ptr指定删除器和shared_ptr有差别:
std::unique_ptr<int,void(*)(int*)>ptr(new int(1),[](int*p){delete p;});
std::weak_ptr
weak_ptr用来监视shared_ptr,不会使引用计数加1,不共享指针,不能操作资源。
基本用法
- 通过use_count()来获得当前观测资源的引用计数
shared_ptr<int> sp(new int(10));
weak_ptr<int> wp(sp);
cout<<wp.use_count()<<endl;//结果为1
- 通过expired()来判断观测的资源是否被释放
shared_ptr<int> sp(new int(10));
weak_ptr<int> wp(sp);
if(wp.expired())
cout<<"监视指针已被释放"<<endl;
- 通过lock()来获取监视的shared_ptr
std::weak_ptr<int> gw;
void f()
{
if (auto spt = gw.lock()) {
std::cout << *spt << "\n";
}
else {
std::cout << "gw is expired\n";
}
}
int main()
{
{
auto sp = std::make_shared<int>(42);
gw = sp;
f();
}
f();
}
输出:
42
gw is expired
weak_ptr解决循环引用
将A或B改为weak_ptr即可。
struct A{
std::shared_ptr<B> bptr;
~A() { cout << "A is deleted!" << endl; }
};
struct B{
std::weak_ptr<A> aptr;
~B() { cout << "B is deleted!" << endl; }
};
void TestPtr(){
std::shared_ptr<A> ap(new A);
std::shared_ptr<B> bp(new B);
ap->bptr = bp;
bp->aptr = ap;
}