shared_ptr用法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
shared_ptr⽤法
引⼊
shared_ptr 是c++为了提⾼安全性⽽添加的智能指针,⽅便了内存管理。
特点
shared_ptr 是通过指针保持对象共享所有权的智能指针。
多个 shared_ptr 对象可占有同⼀对象。
这便是所谓的引⽤计数(reference counting)。
⼀旦最后⼀个这样的指针被销毁,也就是⼀旦某个对象的引⽤计数变为0,这个对象会被⾃动删除。
这在⾮环形数据结构中防⽌资源泄露很有帮助。
使得指针可以共享对象,并且不⽤考虑内存泄漏问题
shared_ptr 可以⽀持普通指针的所有操作,完全可以像操作普通指针⼀样操作智能指针。
shared_ptr 可以通过三种⽅式得到(拷贝初始化,定义delete操作的⽅式不在罗列,只讨论初始化指针所指对象来源):
1.通过⼀个指向堆上申请的空间的指针初始化(切记不要⽤栈上的指针,否则,当智能指针全部释放控制权(栈中的对象离开作⽤域本⾝就会析构⼀次),将会析构对象,导致出错)
2.通过make_shared函数得到
3.通过另外⼀个智能指针初始化
int *a = new int(8);
std::shared_ptr<int> p1(a);
auto b = std::make_shared<int>(2);
auto c(b);
注意事项
1. 使⽤原⽣指针多次初始化
class Base
{
public:
Base() {
printf("con\n");
}
~Base() {
printf("decon\n");
}
};
int main()
{
Base *a = new Base();
std::shared_ptr<Base> p1(a);
std::shared_ptr<Base> p2(a);
return0;
}
这段代码,导致调⽤⼀次构造函数,两次析构函数
2. 使⽤⼀个 shared_ptr 的 get() 初始化另⼀个 shared_ptr
Base *a = new Base();
std::shared_ptr<Base> p1(a);
std::shared_ptr<Base> p2(p1.get());
cppreference 指明这是未定义⾏为
3. 使⽤ shared_ptr 包装 this 指针
class Base
{
public:
Base() {
printf("con\n");
}
~Base() {
printf("decon\n");
}
std::shared_ptr<Base> sget() {
return std::shared_ptr<Base>(this);
}
};
int main()
{
Base b;
std::shared_ptr<Base> p = b.sget();
return0;
}
这会调⽤两次析构函数。
⼀次是b对象析构时,⼀次是智能指针销毁时
正确的使⽤⽅法是:
class Base : public std::enable_shared_from_this<Base>
{
public:
Base() {
printf("con\n");
}
~Base() {
printf("decon\n");
}
std::shared_ptr<Base> sget() {
return shared_from_this();
}
};
int main()
{
std::shared_ptr<Base> b = std::make_shared<Base>();
std::shared_ptr<Base> a = b->sget();
return0;
}
enable_shared_from_this 能让其⼀个对象(假设其名为 t ,且已被⼀个对象 pt 管理)安全地⽣成其他额外的实例(假设名为 pt1, pt2, ... ),它们与 pt 共享对象 t 的所有权。
4. shared_ptr 包装数组
shared_ptr 不能直接包装数组,需要指定数组的析构函数。
不过 shared_ptr 不⽀持取下标操,unique_ptr 是⽀持的
{
public:
Base() {
printf("con\n");
}
~Base() {
printf("decon\n");
}
};
int main()
{
std::shared_ptr<Base> a(new Base[2], [] (Base* p) { delete[] p;
});
return0;
}
5. 循环引⽤
using sb = std::shared_ptr<B>;
class A
{
public:
A() {
printf("A con\n");
}
~A() {
printf("A decon\n");
}
sb b_;
};
class B
{
public:
B() {
printf("B con\n");
}
~B() {
printf("B decon\n");
}
sa a_;
};
int main(int argc, char const *argv[])
{
sa a(new A);
sb b(new B);
a->b_ = b;
b->a_ = a;
return0;
}
对象 a 和 b 都未被析构
正确的⽅法是使⽤ weak_ptr 代替 shared_ptr
using sb = std::shared_ptr<B>;
class A
{
public:
A() {
printf("A con\n");
}
~A() {
printf("A decon\n");
}
std::weak_ptr<B> b_;
};
class B
{
public:
B() {
printf("B con\n");
}
~B() {
printf("B decon\n");
}
std::weak_ptr<A> a_;
};
int main(int argc, char const *argv[])
{
sa a(new A);
sb b(new B);
a->b_ = b;
b->a_ = a;
return0;
}
6. 多线程中使⽤ shared_ptr
shared_ptr的引⽤计数本⾝是安全且⽆锁的,但对象的读写则不是,因为 shared_ptr 有两个数据成员,读写操作不能原⼦化。
shared_ptr 的线程安全级别和内建类型、标准库容器、std::string ⼀样,即:
⼀个 shared_ptr 对象实体可被多个线程同时读取
两个 shared_ptr 对象实体可以被两个线程同时写⼊,“析构”算写操作
如果要从多个线程读写同⼀个 shared_ptr 对象,那么需要加锁。