5.5c++:shared_ptr使用场景,陷阱、性能分析,使用建议(转载)
shared_ptr使用场景
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
shared_ptr <int> create(int value)
{
return make_shared<int> (value);//返回一个shared_ptr
}
//void myfunc(int value)
shared_ptr<int> myfunc(int value)
{
shared_ptr<int> ptmp = create(10);
//return; //离开作用域之后,ptemp会被自动释放,它所指向的内存也会被自动释放。
return ptmp; //系统是根据ptmp这个局部变量来产生一个临时的 shared_ptr对象返回返。
}
int main()
{
//shared_ptr的使用场景
//myfunc(12); //如果这块不用shared_ptr变量来接收myfunc返回的结果,那么从myfunc返回额shared_ptr就会被销毁
auto p11 = myfunc(12);//用一个 shared_ptr来接受,返回的就不会被销毁。
return 0;
}
陷阱
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
void proc(shared_ptr<int> ptr)
{
return ;
}
//class CT
//{
//public:
// shared_ptr<CT> getself()
// {
// return shared_ptr<CT> (this);
// }
//};
class CT:public enable_shared_from_this<CT>
{
public:
shared_ptr<CT> getself()
{
return shared_from_this();//这个就是通过此方法返回智能指针。
}
};
class CB;//声明一下
class CA
{
public:
shared_ptr<CB> m_pbs;
~CA()
{
int test;
test = 1;
}
};
class CB
{
public:
//shared_ptr<CA> m_pas;
weak_ptr<CA> m_pas;
~CB()
{
int test;
test = 1;
}
};
int main()
{
//慎用裸指针
int *p33 = new int(100);//裸指针
//问题1:
//proc(p33); //语法错误,不能使用裸指针传给shared_ptr
//问题2:
//proc(shared_ptr<int> (p));//参数是个 临时的shared_ptr,用一个裸指针显式的构造
//*p = 45;
//参数p传递给形参ptr之后,强引用的引用计数就是1,原来的裸指针指向的对象就汇编被销毁。
//但是,出这个proc函数之后,引用计数就会变成0,此时再*p 就会出问题,因为它早就释放了。
shared_ptr<int> p3(p33);//强引用计数为1
proc(p3);//进入这个函数之后,强引用计数为2,再出来的时候,引用计数变为1.
*p3 = 100;//此时,再赋值也没问题。
// 把一个裸指针帮定到shared_ptr之后,内存管理的责任就到了shared_ptr那么 你就不能再用裸指针来访问这块内存了。
//问题3:
//不要用裸指针来初始化多个shared_ptr
//绝对不可以,绝对不可以,绝对不可以
// int *k = new int(122);
// shared_ptr<int>kp(k);
// shared_ptr<int>kp2(k);
// cout << kp.get() <<endl;//地址相同,这样就会被释放2次,同一块内存,释放两次就会出错。
// cout << kp2.get() <<endl;
// cout<<kp.use_count()<<endl;//1
// cout<<kp2.use_count()<<endl;//1
//建议使用的方法
shared_ptr<int> p1(new int);
shared_ptr<int> p2(p1);//p1p2的控制块是互通的,可以解决上面的问题。
//问题4:慎用get()返回的地址
//返回智能指针指向的对应的裸指针。(有些函数接口可能只能使用裸指针)
//(4.1)get返回的指针不能delete,否则异常。
// shared_ptr<int> myp(new int(122));
// int *p4 = myp.get();
// // delete p;//不可以删除
//(4.2)不能将其它智能指针绑到get返回的指针上。
// shared_ptr<int> myp (new int(122));
// int *p = myp.get();//这个指针千万不能随意释放。
// {
// shared_ptr<int> myp2(p);//myp 和 myp2引用计数都为1,一旦跳出程序块
// }//离上面的作用范围,导致myp指向的内存被释放
// *myp = 65; //该内存已经被释放,这样赋值会导致不可预料的后果。
//问题(5):不要把类对象指针(this)作为shared_ptr返回。改用enable_shared_from_this;
//没问题:
// shared_ptr<CT> pct1(new CT);
// shared_ptr<CT> pct2 = pct1;//这是两个强引用
//有问题
// shared_ptr<CT> pct1(new CT);
// shared_ptr<CT> pct2 = pct1->getself();//问题出现 两个shared_ptr对象控制块不同,就会被释放两次
//用到c++标准库里边的类模板 :enable_shared_from_this
shared_ptr<CT> pct1(new CT);
shared_ptr<CT> pct2 = pct1->getself();
//enable_shared_from_this中有一个弱指针,weak_ptr能够监视this
//在我们调用shared_from_this()这个方法的时候,这个方法内部实际上是调用了
//weak_ptr的lock()方法,让shared_ptr指针计数加1,同时返回shared_ptr
//问题(6):避免循环引用:能够导致内存泄露
//
// shared_ptr<CA> pca(new CA);
// shared_ptr<CB> pcb(new CB);
// pca->m_pbs = pcb;//引用计数变为2,离开作用域之后还是1
// pcb->m_pas = pca;//引用计数变为2,离开作用域之后还是1
//最终都没调用析构函数。都泄露了。
//解决方法:就是把其中任何一个改成 弱引用,就可以了
shared_ptr<CA> pca(new CA);//1
shared_ptr<CB> pcb(new CB);//1
pca->m_pbs = pcb;//CB引用计数变为2
pcb->m_pas = pca;
//因为是weak_ptr所以指向CA对象的只有一个强引用
//离开作用域后,pca从1变道0,就会被释放。
//导致CA内的m_pbs引用计数减1,最终都为0
}
性能分析
#include <iostream>
#include <vector>
#include <memory>
using namespace std;
int main()
{
// 性能说明
//(一)尺寸问题:
//shared_ptr和weak_ptr 都是裸指针的两倍
//控制块创建时机:
//a)make_shared:分配并初始化一个对象,返回shared_ptr,
//b) 用裸指针来创建一个shared_ptr对象的时候。
// 所以不允许用裸指针创建多个对象.强引用计数都为1.
//(二)移动语句
shared_ptr <int> p1 (new int(122));
shared_ptr <int> p2 (std::move(p1));//移动语句 移动构造一个新的智能指针对象
//p1就不再指向该对象(变成空),引用计数依旧是1
shared_ptr<int> p3;
p3 = sed::move(p2); //移动赋值,p2指向空,p3指向该对象,引用计数仍为1
//移动肯定比复制快,复制需要增加引用计数,移动不需要
//移动构造函数快过复制构造函数,移动赋值运算符快过拷贝赋值运算符。
}
补充说明和使用建议
//分配器
//shared_ptr<int> p ((new , int) , mydelete(),myallocator<int>());
//优先使用make_shared() //分配一次内存,尽管不能定义自己的删除器