目录
其他补充
尺寸问题
移动语义
shared_ptr错误范例
裸指针:
#include<iostream>
using namespace std;
void Test(shared_ptr<int> ps)
{return;
}
int main()
{int *p=new int(666);Test(p);
//E0415 不存在从 "int *" 转换到 "std::shared_ptr<int>" 的适当构造函数
//shared_ptr是禁止隐式类型转换的,有explicit属性Test(shared_ptr<int>(p));//临时shared_ptr对象*p=555;
//系统不报错,但是我们使用了已经被释放的内存。p在Test结束时就已经被智能指针释放。shared_ptr<int> pi1(p);shared_ptr<int> pi2(p);
//编译时报错,这样用裸指针初始化多个shared_ptr对象,pi1与pi2的引用计数并不关联。导致系统报错}
//裸指针和智能指针混用会带来很多不引人注意的问题。如果使用裸指针给智能指针初始化,就不要再使用该裸指
//针了。更不要使用裸指针给多个shared_ptr对象初始化
get():
#include<iostream>
using namespace std;
int main()
{shared_ptr<int> ps(new int(666));int *p=ps.get();//这样获得的裸指针不要再delete。shared_ptr<int> ps2(p);
//这样也会导致ps与ps2的引用计数不相关联,系统异常。
}
//不要用get()得到的裸指针初始化shared_ptr对象
将this指针作为shared_ptr对象返回:
#include<iostream>
using namespace std;
class CT
{
public:shared_ptr<CT> getself(){return shared_ptr<CT>(this);}
}
int main()
{shared_ptr<CT> ps1(new CT);shared_ptr<CT> ps2=ps1->getself();
//这样同样导致ps1与ps2的引用计数不关联,导致异常
//这时我们可以使CTpublic继承enable_shared_from_this(c++标准库中的模板类),
//再使用return enable_shared_from_this;代替return shared_ptr<CT>(this);
//就可以保证代码的正确了(其实是使用了weak_ptr的lock()功能)
}
循环引用:
#include<iostream>
using namespace std;
class A
{
public:shared_Ptr<B> pb;~A() {}
};
class B
{
public:shared_ptr<A> pa;~B() {}
};
int main()
{shared_ptr<A> mpa(new A);shared_ptr<B> mpb(new B);mpa->pb=mpb;mpb->pa=mpa;
}//这样会造成死锁问题。mpa和mpb的析构函数都不会被释放,造成内存泄露。
//解决方案是将类中任意一个shared_ptr改为weak_ptr。
其他补充
尺寸问题
shared_ptr与weak_ptr对象占用的内存都是裸指针的两倍。例如shared_ptr是int *的两倍,也就是8字节。在这两倍的内存中,实际上包含两个裸指针。一个指向我们需要的对象,另一个指向控制块,控制块中包含着一些需要记录的内容,如强引用计数,弱引用计数,自定义的删除器,分配器等。当我们生成第一个指向某对象的shared_ptr对象时,控制块就会同时被分配出来。当我们用shared_ptr对象生成weak_ptr对象时,weak_ptr对象中的指针就会指向shared_ptr指向的对象,另一个指向该 shared_ptr对象指向的控制块,就是说,指向同一个对象的shared_ptr对象和weak_ptr对象指向同一个控制块。这也说明了weak_ptr的生成要依赖shared_ptr对象的原因,因为weak_ptr对象并不能自主生成控制块,必须提供shared_ptr对象给出供它指向的控制块。
移动语义
shared_ptr<int> p1=make_shared<int>(666);
shared_ptr<int> p2(std::move(p1));
//引用计数依旧为1,p1变为空
相比拷贝构造函数,移动构造函数的速度更快,且不增加引用计数。