智能指针

https://media.githubusercontent.com/media/irisHYT/ImageHosting0/main/images/1690861871031.webp

智能指针依赖C++自行调用析构函数的特点,使用对象的生命周期来自动管理在堆空间申请的内存。

auto_ptr

auto_ptr在C++98中就存在,本身存在明显的问题。

所有权转义

当auto_ptr进行相互赋值操作之后,会进行所有权转移,老的指针会被设置为空指针,后续只能使用新的指针进行解引用等操作。

1#include <memory>
2using namespace std;
3int main() {
4	auto_ptr<int> p1(new int);
5	auto_ptr<int> p2 = p1;
6	*p1 = 1; // 此时对象的操作权限已经转移到p2上,p1被置空。
7	return 0;
8}

导致以下问题:

  • 不能结合STL容器使用

不适用于管理数组

auto_ptr在析构时使用的方法为delete,而当析构数组时,需要使用delete[],所以不能用auto_ptr管理数组指针。

1#include <memory>
2using namespace std;
3int main() {
4	int n = 100000;
5	while (n--) {
6		auto_ptr<int> p1(new int[10000]);
7	} // 产生内存泄漏
8	return 0;
9}

unique_ptr

unique_ptr出现于C++11,不支持拷贝和赋值操作,只能通过右值引用的方式转移资源的所有权。默认情况下于auto_ptr一样使用delete来析构资源,但也可以通过自定义删除器来实现对资源的析构操作,支持lambda表达式实现自定义删除器,同时支持了对数组资源的管理。

删除拷贝构造和赋值操作

 1#include <mempry>
 2using namespace std;
 3int main() {
 4	unique_ptr<int> p1(new int(32));
 5	// unique_ptr<int> p2(p1); 拷贝构造函数产生编译报错
 6	// unique_ptr<int> p2 = p1; 赋值操作产生编译报错
 7	unique_ptr<int> p2(std::move(p1)); // 将p1转义为右值即可以调用移动构造函数
 8	unique_ptr<int> p3 = std::move(p2); // 同样可以实现资源的所有权转移
 9	return 0;
10}

支持管理数组

1#include <memory>
2using namespace std;
3int main() {
4	unique_ptr<int[]> p(new int[100]);
5	return 0;
6}

自定义删除器

 1#include <memory>
 2#include <iostream>
 3using namespace std;
 4class A {};
 5class ADeleter1 {
 6public:
 7	void operator()(A* p) {
 8		cout << "deleted p 1" << endl;
 9	}
10};
11
12void ADeleter2(A* p) {
13	cout << "deleted p 2" << endl;
14}
15int main() {
16	unique_ptr<A, ADeleter1> p(new A);
17	unique_ptr<A, decltype(ADeleter2)*> p(new A, ADeleter2);
18	return 0;
19}

shared_ptr

shared_ptr出现于C++11,采用引用计数的方法,解决了auto_ptrunique_ptr存在的问题,同时也支持指定删除器。但shared_ptr也存在自己的问题。

循环引用

 1#include <memory>
 2#include <iostream>
 3using namespace std;
 4class A {
 5public:
 6	shared_ptr<B> b;
 7	~A() {
 8		cout << "delete A" << endl;
 9	}
10};
11class B {
12public:
13	shared_ptr<A> a;
14	~B() {
15		cout << "delete B" << endl;
16	}
17}
18int main() {
19	shared_ptr<A> pa(new A);
20	shared_ptr<B> pb(new B);
21	pa->b = pb;
22	pb->a = pa;
23	return 0;
24}

当两个类互相持有对方的shared_ptr并相互指向时,引用计数会被置为2,当生命周期到达时,会使拥有的shared_ptr计数为1,所以并没有执行对应的析构函数,导致内存泄漏。

weak_ptr

weak_ptr出现于C++11,用来解决shared_ptr的循环引用问题,只能使用weak_ptr或者shared_ptr构造,weak_ptr的赋值操作不会使shared_ptr的引用计数变化。weak_ptr不能对指针进行解引用操作,类似只读的操作,但可以通过lock方法拷贝一个shared_ptr进行操作,当资源已经被析构时,调用lock方法会返回一个空的shared_ptr

Latest Posts