std::unique_ptr

std::unique_ptr是一个独占所有权的指针,同一时间只能有一个std::unique_ptr 指向给定对象,当std::unique_ptr被销毁时,它指向的对象也会被释放;

动手试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include<iostream>
#include<memory>
struct A {
std::unique_ptr<int> u_ptr;
A() {
std::cout << "construct A" << std::endl;
}
~A() {
std::cout << "destruct A" << std::endl;
}
};

int main() {
std::unique_ptr<A> u_ptr(new A());
return 0;
}

std::shared_ptr

std::shared_ptr是一个共享所有权的智能指针,同一时间可以有多个 shared-ptr 指向给定对象,内部引用计数来统计引用数量,只有在最后一个 shared_ptr 被销毁时,指向的对象才会被释放;

std::shared_ptr的循环引用

如果两个 shared_ptr 相互引用,就会形成循环引用,导致两个 shared_ptr 对象不被释放,造成内存泄漏;

动手试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>
#include<memory>

struct B;

struct A {
std::shared_ptr<B> s_ptr;
A() {
std::cout << "construct A" << std::endl;
}
~A() {
std::cout << "destruct A" << std::endl;
}
};

struct B {
std::shared_ptr<A> s_ptr;
B() {
std::cout << "construct B" << std::endl;
}
~B() {
std::cout << "destruct B" << std::endl;
}
};

int main() {
std::shared_ptr<A> a = std::make_shared<A>();
std::shared_ptr<B> b = std::make_shared<B>();

a->s_ptr = b;
b->s_ptr = a;

std::cout << "main end" << std::endl;
return 0;
}

输出:

1
2
3
4
5
Program returned: 0
construct A
construct B
main end
# 程序结束了,但是a, b 没有调用析构函数,因为循环引用,a 和 b 的引用计数不会降为 0,他们的析构函数不会被调用,a,b没有被删除

循环引用需要使用 weak_ptr 来解决,weak_ptr 是不控制对象的生命周期的智能指针,它指向一个 shared_ptr管理的对象。当对象的所有 shared_ptr都消失后,即使还有 weak_ptr 指向该对象,该对象也会被正常销毁。

实现一个简单的 shared_ptr

shared_ptr 主要有两个成员变量:数据指针和计数指针;

需要实现他的构造函数、析构函数、拷贝构造、赋值运算符=重载、解引用运算符*重载、成员访问运算符->重载、以及获取引用计数函数。

动手试一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include <iostream>

template <typename T>
class SharedPtr {
public:
explicit SharedPtr(T* p = nullptr) :ptr(p), ref_count(new size_t(1)) {}

SharedPtr(const SharedPtr& p) :ptr(p.ptr), ref_count(p.ref_count) {
(*ref_count)++;
}

~SharedPtr() {
if (--(*ref_count) == 0) {
delete ptr;
delete ref_count;
}
}

SharedPtr& operator=(const SharedPtr& p) {
if (this != &p) {
if (--(*ref_count) == 0) {
delete ptr;
delete ref_count;
}
ptr = p.ptr;
ref_count = p.ref_count;
++(*ref_count);
}
return *this;
}

T& operator*() {
return *ptr;
}

T* operator->() {
return ptr;
}

size_t use_count() {
return (*ref_count);
}

private:
T* ptr;
size_t* ref_count;
};

int main() {
SharedPtr<int> p1(new int(5));
std::cout << p1.use_count() << std::endl;

SharedPtr<int> p2 = p1;
std::cout << "p1 use count: " << p1.use_count() << std::endl;
std::cout << "p2 use count: " << p2.use_count() << std::endl;

SharedPtr<int> p3;
p3 = p1;
std::cout << "p1 use count: " << p1.use_count() << std::endl;
std::cout << "p2 use count: " << p2.use_count() << std::endl;
std::cout << "p3 use count: " << p3.use_count() << std::endl;
}