share_ptr常用操作,计数和自定义删除器
1. share_ptr常用操作,计数和自定义删除器
—use_count 成员函数,用于返回多少个智能指针指向某个对象,这个成员函数主要是用来做调试,效率不高
shared_ptr<int> myp(new int(100));
int icount = myp.use_count(); //1
shared_ptr<int> myp2(myp);
icount = myp.use_count(); //2
shared_ptr<int> myp3;
myp3 = myp2;
icount = myp.use_count(); //3
icount = myp3.use_count(); //3
—unique成员函数,是否只有一个智能指针指向某个对象,是的话是true,不是则false
share_ptr<int> myp(new int(100));
if(myp.unique()) // 条件成立
{
//myp独占所指向的对象
cout << "myp unique ok" << endl;
}
shared_ptr<int> myp2(myp);
if(myp.uninque()) // 条件不成立
{
cout << "myp unique ok" << endl;
}
—reset成员函数,分三种情况
1.1第一种,若reset不带参数时
如果pi是唯一指向该对象的指针,则释放pi指向的对象,把pi置空
如果pi不是唯一指向该对象的指针,则不释放pi指向的对象,但指向该对象引用计数会减1,同时将pi置空
shared_ptr<int> pi(new int(100));
pi.reset(); //释放pi指向的对象,将pi置空
if(pi == nullptr)
{
cout << "pi被置空" << endl;
}
继续看如果pi不是唯一指向该对象指针的情形
shared_ptr<int> pi(new int(100));
auto pi2(pi); //pi2现在引用计数为2
pi.reset();//pi被置空,pi2现在引用计数为1
1.2第二种,当reset带参数(一般是一个new出来的指针)时
如果pi是唯一指向该对象的指针,则释放pi指向的对象,让pi指向新内存
如果pi不是唯一指向该对象的指针,则不释放pi指向的对象,但指向该对象引用计数会减1,同时让pi指向新内存
shared_ptr<int> pi(new int(100));
pi.reset(new int(1)); //释放原内存(内容为100的内存),指向新内存(内容为1的内存)
继续看如果pi不是唯一指向该对象指针的情形
shared_ptr<int> pi(new int(100));
auto pi2(pi); //pi2现在引用计数为2
pi.reset(new int(1));//现在pi引用计数为1,上面的pi2引用计数为1
if(pi.unique()) //成立
{
cout << "pi unique ok" << endl;
}
if(pi2.unique()) //成立
{
cout << "pi unique ok" << endl;
}
1.3第三种,空指针也可以通过reset来重新初始化
shared_ptr<int> p; //p现在是空指针
p.reset(new int(100)); //释放p指向的对象,让p指向新内存,因为原来p为空,所以就等于啥也没释放
—*解引用
*p:获得p指向的对象
shared_ptr<int> pother(new int(12345));
char outbuf[1024];
sprintf_s(outbuf, sizeof(outbuf), "%d", *pother); //outbuf中的内容就是12345,pother不发生任何变化,引用计数仍然为1
—get成员函数
p.get() :返回p中保存的指针,小心使用,如果智能指针释放了所指向的对象,则返回这个指针所指向的也就变的无效了
shared_ptr<int> myp(new int(100));
int *p = myp.get();
*p = 45;
为什么要有这样一个函数呢,主要是考虑到有些函数的参数需要的是一个内置指针(裸指针),所以需要通过get取得这个内置指针并传递给这样的函数,但要主要不要delete这个get到的指针,否则有不可预料后果
1.4—swap成员函数
用于交换两个智能指针所指向的对象,当然因为是交换,所以引用计数并不发生变化
shared_ptr<string> ps1(new string("I love China1"));
shared_ptr<string> ps2(new string("I love China2"));
std::swap(ps1, ps2); //可以
ps1.swap(ps2) //也可以
1.5—nullptr两个用途
第一,把所指向对象的引用计数减1,若引用计数变为0,则释放智能指针所指向的对象
第二,将智能指针置空
shared_ptr<string> ps1(new string("I love China"));
ps1 = nullptr;
1.6—智能指针的名字作为判断条件
shared_ptr<string> ps1(new string("I love China"));
if(ps1) //成立
{
cout << "ps1" << endl;
}
1.7—指定删除器和数组问题,分两条
第一是指定删除器
智能指针是怎么自动删除所指向对象呢,delete
同时程序员也可以指定自己的删除其,这样当智能指针删除时,调用的就是程序员自己写的,而不是默认的delete
shared_ptr指定删除其比较简单,一般只需要在参数中添加具体的删除器函数名即可(注意,删除器是一个单形参的函数)
void myDeleter(int * p); // 自己的删除器,删除整型指针用的,当p的引用计数为0,自动调用这个删除器删除对象,释放内存
{
delete p;
}
在main中
shared_ptr<int> p(new int(12345), myDeleter); //指定删除器
shared_ptr<int> p2(p); //现在两个引用计数指向该对象
p2.reset(); //现在一个引用计数指向该对象,p2为nullptr
p.reset(); //此时只有一个指针指向该对象,所以释放指向的对象,调用自己的删除器myDeleter,同时把p置空
删除器也可以是一个lambda表达式,注意用{}包着的是lambda表达式的组成部分,直接作为一个参数使用
shared_ptr<int> p (new int(12345),[](int * p){
delete p;
});
p.reset(); //会调用删除器
为什么不用默认的删除器的,因为有些默认的删除器用不了,比如用shared_ptr管理动态数组的时候,就需要指定自己的删除器,默认的删除器不支持数组对象
shared_ptr<int[]> p(new int[10], [](int*p){
delete[] p;
})
p.reset;
回想之前的内容,如果一个类定义中有析构函数,则程序员必须自己指定删除器,否则会异常
class A
{
public:
A()
{
cout << "A()的构造被调用" << endl;
}
~A()
{
cout << "~A()的析构被调用" << endl;
}
}
在main中
shared_ptr<A> pA(new A[10]); //异常,因为系统释放的是pA是使用delete pA而不是使用delete[] pA,所以必须自己写删除器
像这样修改代码,就可以解决
shared_ptr<A> pA(new A[10], [](A*p){
delete[] p;
});
此外,还可以将default_delete作为删除器,这是一个标准库里的类模板,这个删除器的内部也是通过delete来实现功能的:
shared_ptr<A> pA(new A[10], std::default_delete<A[]>());
很多时候程序员做的工作都是为了保证数组正常释放,其实在定义时候这样写,即使自己不写删除器也可以正常释放内存
shared_ptr<A[]> pA(new A[10]); //<>中加个[]就行了
shared_ptr<int[]> p(new int[10]); //<>中加个[]就行了,并且加了[]后,引用也方便,比如说p[0],p[1],,,,p[9]直接拿来用
所以最好在定义数组时在尖括号<> 中都要加[]
另外也可以自己写个函数模板封装shared_ptr数组
//定义一个函数模板,解决shared_ptr管理动态数组的情形
template<typename T>
shared_ptr<T> make_shared_array(size_t size)
{
return shared_ptr<T>(new T[size], default_delete<T[]>()); //指定了删除器
}
在main里
shared_ptr<int> pinArr = make_shared_array<int>(5);//末尾数字代表数组元素个数
第二是,指定删除器的额外说明
就算这两个shared_ptr指定的删除器不相同,只要他们所指向的对象相同,那么这两个shared_ptr也是属于一个类型的
在main中
auto lambda1 = [](int*p)
{
delete p;
};
auto lambda2 = [](int*p)
{
delete p;
};
shared_ptr<int> p1(new int(100), lambda1); //指定lambda1为删除器
shared_ptr<int> p2(new int(200), lambda2); //指定lambda1为删除器
p2 = p1;//p2会先调用lambda2把自己所指向对象释放,然后指向p1所指对象,现在该对象引用计数为2,整个main函数执行完毕之前还会调用lambda1释放p1,p2共同所指向的对象
同一个类型有一个好处是可以放到元素类型为该对象类型的容器里,方便操作
继续在main里面
vector<shared_ptr<int>> pvec{p1, p2};//
- 点赞
- 收藏
- 关注作者
评论(0)