文章目录
表12.1列出了 shared_ptr 和 unique_ptr 都支持的操作。只适用于 shared_ptr 的操作列于表12.2中。
1.use_count()
返回多少个智能指针指向某个对象,主要用于调试目的。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> p1(new int(100));
cout << p1.use_count() << endl; // 1
shared_ptr<int> p2(p1);
cout << p1.use_count() << endl; // 2
shared_ptr<int> p3;
p3 = p2;
cout << p1.use_count() << endl; // 3
cout << p3.use_count() << endl; // 3
return 0;
}
2.unique()
判断该智能指针是否独占某个指向的对象,也就是说,若只有一个智能指针指向某个对象,则 unique() 返回 true,否则返回 false。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> p1(new int(100));
if (p1.unique()) cout << "unique" << endl; // unique
else cout << "not unique" << endl;
shared_ptr<int> p2(p1);
if (p2.unique()) cout << "unique" << endl;
else cout << "not unique" << endl; // not unique
shared_ptr<int> p3;
if (p3.unique()) cout << "unique" << endl;
else cout << "not unique" << endl; // not unique
return 0;
}
3.reset()
p.reset()
不带参数时:
- 若 p 是唯一指向该对象的指针,那么释放 p 所指向的对象,并将 p 置空。
- 若 p 不是唯一指向该对象的指针,那么不释放 p 所指向的对象,但指向该对象的引用计数会减少 1 1 1,同时将 p 置空。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> p1(new int(100));
p1.reset(); // 释放p1所指向的内存,并将p1置nullptr
cout << p1.use_count() << endl; // 0
return 0;
}
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> p1(new int(100));
auto p2(p1);
cout << p2.use_count() << endl; // 2
p1.reset(); // 不释放p1所指向的对象,但指向该对象的引用计数会减少1,同时将p1置nullptr
cout << p2.use_count() << endl; // 1
return 0;
}
p.reset()
带参数(一般是一个new出来的指针)时:
- 若 p 是唯一指向该对象的指针,则释放 p 指向的对象,让 p 指向新对象。
- 若 p 不是唯一指向该对象的指针,则不释放 p 指向的对象,但指向该对象的引用计数会减少 1 1 1,同时让 p 指向新对象。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> p1(new int(100));
cout << p1.use_count() << endl; // 1
p1.reset(new int(1)); // 释放原内存,指向新内存
cout << p1.use_count() << endl; // 1
return 0;
}
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> p1(new int(100));
auto p2(p1);
cout << p1.use_count() << endl; // 2
cout << p2.use_count() << endl; // 2
p1.reset(new int(10)); // 不释放p1所指向的对象,但指向该对象的引用计数会减少1,同时让p1指向新对象
cout << p1.use_count() << endl; // 1
cout << p2.use_count() << endl; // 1
return 0;
}
空指针也可以通过 reset 来重新初始化。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> p;
p.reset(new int(10)); // 释放p所指向的对象,让p指向新对象。因为p原来就为空,所以就等于啥也没释放直接指向新对象
return 0;
}
4.解引用
*p
解引用:获得 p
指向的对象。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> p(new int(123456));
cout << *p << endl; // 123456
return 0;
}
5.get()
p.get()
:返回 p
中保存的指针(裸指针)。
如果智能指针释放了所指向的对象,那么这个返回的裸指针也就变得无效了。
考虑到有些第三方库的函数的参数需要的是一个内置裸指针而不是智能指针,所以引入了 get() 函数。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> sp(new int(100));
int* p = sp.get();
*p = 45;
//delete p; // 千万不要这么干,否则系统会报告异常,产生不可预料的结果
return 0;
}
6.swap()
swap():交换两个智能指针所指向的对象。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<string> sp1(new string("Hello"));
shared_ptr<string> sp2(new string("World"));
std::swap(sp1, sp2); // 等价于sp1.swap(sp2);
return 0;
}
7.p = nullptr
p = nullptr
干了两件事:
- 将智能指针置空;
- 将所指向的对象引用计数减 1 1 1,若引用计数变为 0 0 0,则释放智能指针所指向的对象。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<string> sp1(new string("hello"));
shared_ptr<string> sp2(sp1);
cout << sp2.use_count() << endl; // 2
sp1 = nullptr;
cout << sp2.use_count() << endl; // 1
return 0;
}
8.智能指针名字作为判断条件
#include <iostream>
using namespace std;
int main()
{
shared_ptr<string> sp(new string("hello"));
if (sp) cout << "sp指向一个对象" << endl; // sp指向一个对象
else cout << "sp为空" << endl;
sp = nullptr;
if (sp) cout << "sp指向一个对象" << endl;
else cout << "sp为空" << endl; // sp为空
return 0;
}
9.指定删除器
我们可以指定自己的删除器取代系统提供的默认删除器。当智能指针需要删除所指向的对象时,编译器就会调用我们自己提供的删除器来删除。
注意:虽然 make_shared 是提倡的初始化 shared_ptr 的方法,但是 make_shared 没有办法让我们指定自己的删除器。
9.1 普通函数做删除器
shared_ptr 指定删除器方法比较简单,一般只需要在参数中添加具体的删除器函数名即可。
#include <iostream>
using namespace std;
// 当智能指针引用计数为0时,就会自动调用该删除器来删除对象
void myDelete(int* p)
{
delete p; // 既然自己提供了删除器来取代智能指针的默认删除器,那就有义务自己来删除所指向的对象
}
int main()
{
shared_ptr<int> p1(new int(123456), myDelete);
shared_ptr<int> p2(p1);
p2.reset(); // reset后,p2被置nullptr,引用计数从2变为1
p1.reset(); // reset后,p1被置nullptr,引用计数从1变为0,此时调用我们的删除器myDelete释放所指向的对象
return 0;
}
9.2 lambda表达式做删除器
删除器可以是一个 lambda 表达式。
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> sp(new int(123456), [](int* p) {
delete p;
});
return 0;
}
注意:就算是两个 shared_ptr 指定了不同的删除器,只要它们所指向的对象类型相同,那么这两个 shared_ptr 也属于同一个类型。
#include <iostream>
using namespace std;
int main()
{
auto lambda1 = [](int* p) {
cout << "lambda1" << endl;
delete p;
};
auto lambda2 = [](int* p) {
cout << "lambda2" << endl;
delete p;
};
shared_ptr<int> p1(new int(100), lambda1);
shared_ptr<int> p2(new int(200), lambda2);
p2 = p1; // p2会先调用lambda2释放自己所指的对象,然后指向p1所指的对象,此时p1所指对象的引用计数为2
// 整个main函数执行完毕后,会调用lambda1来释放p1、p2共同指向的对象
return 0;
}
9.3 数组问题
有些情况,默认删除器处理不了,比如用 shared_ptr 管理动态数组,需要我们提供自己指定的删除器。
举例1:
#include <iostream>
using namespace std;
int main()
{
shared_ptr<int> sp(new int[10], [](int* p) {
delete[] p;
});
return 0;
}
举例2:
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A()" << endl; }
~A() { cout << "A::~A()" << endl; }
};
int main()
{
shared_ptr<A> sp(new A[10], [](A* p) {
delete[] p;
});
return 0;
}
可以用 default_delete 做删除器,default_delete 是标准库里的模板类。
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A()" << endl; }
~A() { cout << "A::~A()" << endl; }
};
int main()
{
shared_ptr<A> sp(new A[10], std::default_delete<A[]>());
return 0;
}
最简单的方法:定义数组的时候,我们在尖括号中加个 []
就可以了。
#include <iostream>
using namespace std;
class A
{
public:
A() { cout << "A::A()" << endl; }
~A() { cout << "A::~A()" << endl; }
};
int main()
{
shared_ptr<A[]> sp(new A[10]);
return 0;
}