智能指针
C++ 智能指针的底层实现是通过 RAII(Resource Acquisition Is Initialization,资源获取即初始化)和引用计数来管理动态分配的内存或资源,避免手动管理内存带来的问题,如内存泄漏和悬空指针。C++ 标准库中提供了几种常见的智能指针类型:std::unique_ptr
、std::shared_ptr
和 std::weak_ptr
。以下是它们的基本底层实现原理。
# 1. std::unique_ptr
std::unique_ptr
是一种独占所有权的智能指针,表示某个指针只能由一个 unique_ptr
拥有。当 unique_ptr
超出作用域时,自动销毁所管理的对象。
# 底层实现
成员变量:
unique_ptr
通常持有一个原生指针,用于指向所管理的对象。构造与析构:
- 在构造时,
unique_ptr
接受一个原生指针,并将它存储在内部。 - 在析构时,
unique_ptr
会自动调用delete
来销毁所管理的对象。
- 在构造时,
禁止拷贝:
- 通过删除拷贝构造函数和拷贝赋值操作符,确保
unique_ptr
的唯一所有权特性。
- 通过删除拷贝构造函数和拷贝赋值操作符,确保
移动语义:
- 通过实现移动构造函数和移动赋值操作符,使得所有权可以在不同的
unique_ptr
之间转移。
- 通过实现移动构造函数和移动赋值操作符,使得所有权可以在不同的
template<typename T>
class unique_ptr {
private:
T* ptr;
public:
explicit unique_ptr(T* p = nullptr) : ptr(p) {}
~unique_ptr() {
delete ptr;
}
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
unique_ptr(unique_ptr&& other) noexcept : ptr(other.ptr) {
other.ptr = nullptr;
}
unique_ptr& operator=(unique_ptr&& other) noexcept {
if (this != &other) {
delete ptr;
ptr = other.ptr;
other.ptr = nullptr;
}
return *this;
}
T* get() const { return ptr; }
T& operator*() const { return *ptr; }
T* operator->() const { return 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
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
# 2. std::shared_ptr
std::shared_ptr
是一种具有共享所有权的智能指针,允许多个 shared_ptr
实例管理同一个对象。当最后一个 shared_ptr
销毁时,对象才会被释放。
# 底层实现
成员变量:
- 原生指针:指向被管理的对象。
- 控制块(Control Block):存储引用计数、弱引用计数以及管理的对象的指针。
控制块:
- 引用计数:用于跟踪有多少个
shared_ptr
实例共享该对象。 - 弱引用计数:用于跟踪
std::weak_ptr
实例的数量。 - 当引用计数减为零时,释放对象;当弱引用计数也为零时,释放控制块。
- 引用计数:用于跟踪有多少个
构造与析构:
- 在构造时,创建或共享控制块,并增加引用计数。
- 在析构时,减少引用计数。如果引用计数为零,则释放所管理的对象。
线程安全:
shared_ptr
的引用计数操作是线程安全的。
template<typename T>
class shared_ptr {
private:
T* ptr;
ControlBlock* controlBlock;
public:
shared_ptr(T* p = nullptr) : ptr(p) {
if (ptr) {
controlBlock = new ControlBlock(p);
}
}
~shared_ptr() {
if (controlBlock && --controlBlock->ref_count == 0) {
delete ptr;
if (controlBlock->weak_count == 0) {
delete controlBlock;
}
}
}
shared_ptr(const shared_ptr& other) : ptr(other.ptr), controlBlock(other.controlBlock) {
if (controlBlock) {
++controlBlock->ref_count;
}
}
shared_ptr& operator=(const shared_ptr& other) {
if (this != &other) {
// 减少旧的引用计数
if (controlBlock && --controlBlock->ref_count == 0) {
delete ptr;
if (controlBlock->weak_count == 0) {
delete controlBlock;
}
}
// 增加新的引用计数
ptr = other.ptr;
controlBlock = other.controlBlock;
if (controlBlock) {
++controlBlock->ref_count;
}
}
return *this;
}
T* get() const { return ptr; }
T& operator*() const { return *ptr; }
T* operator->() const { return 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
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
# 3. std::weak_ptr
std::weak_ptr
是与 shared_ptr
搭配使用的智能指针,它不影响所管理对象的生命周期,而是提供对 shared_ptr
所管理对象的弱引用。它主要用于解决循环引用问题。
# 底层实现
弱引用:
weak_ptr
持有对控制块的弱引用,而不直接持有对对象的引用。- 当
weak_ptr
需要访问对象时,会尝试提升(lock
)为shared_ptr
,如果对象已被销毁,则提升失败。
控制块:
weak_ptr
的创建和销毁会影响控制块中的弱引用计数,但不影响对象的引用计数。
# 4. 总结
std::unique_ptr
提供了简单而高效的独占所有权管理,避免了复制和共享。std::shared_ptr
使用引用计数管理共享对象的生命周期,支持多方共享同一资源。std::weak_ptr
通过弱引用解决了循环依赖问题,在不增加引用计数的情况下访问对象。
编辑 (opens new window)
上次更新: 2024/09/13, 11:59:12