共享智能指针 (std::shared_ptr)

共享智能指针 (std::shared_ptr)
枫在 C++ 中,智能指针(Smart Pointers)是用于管理动态分配内存的工具,可以自动释放内存,避免内存泄漏。它们在 C++11 及后续标准中通过标准库
提供,主要包括以下三种类型:
C++11中提供了三种智能指针,使用这些智能指针时需要引用头文件:
- std::shared_ptr: 共享智能指针
- std::unique_ptr: 独占智能指针
- std::weak_ptr: 弱引用的智能指针,它不共享指针,不能操作资源,是用来监视shared_ptr的。
1.shared_ptr的初始化
在 C++ 中,std::shared_ptr 的初始化有多种方式,推荐使用安全且高效的方法。以下是 std::shared_ptr 的常见初始化方式及注意事项:
1.使用 std::make_shared初始化(推荐)
- 方式: 通过 std::make_shared 创建 std::shared_ptr,这是 C++11 引入的首选方法
- 优点:
- 更高效:一次性分配对象和引用计数控制块的内存。
- 更安全:避免了直接使用 new 可能导致的异常问题。
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct MyClass {
int value;
MyClass(int v) : value(v) {}
~MyClass() { std::cout << "Destroyed\n"; }
};
int main() {
std::shared_ptr<MyClass> ptr = std::make_shared<MyClass>(42);
std::cout << ptr->value << "\n"; // 输出 42
return 0; // 自动释放
} - 适用场景:大多数情况下创建 shared_ptr 的首选方式。
2.通过构造函数和new初始化
- 方式: 直接将 new 分配的指针传入 std::shared_ptr 构造函数。
- 缺点:
- 性能稍差:new 和控制块分配是分开的。
- 不安全:如果在构造 shared_ptr 前抛出异常,可能导致内存泄漏。
- 示例:
1
2
3
4
5
6
7
8
9
10
11
struct MyClass {
~MyClass() { std::cout << "Destroyed\n"; }
};
int main() {
std::shared_ptr<MyClass> ptr(new MyClass());
return 0; // 自动释放
} - 注意:尽量避免此方式,优先使用 std::make_shared。
3.通过另一个 shared_ptr 初始化(共享所有权)
- 方式:通过拷贝构造或赋值操作,多个 shared_ptr 共享同一资源,引用计数增加。
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct MyClass {
~MyClass() { std::cout << "Destroyed\n"; }
};
int main() {
std::shared_ptr<MyClass> ptr1 = std::make_shared<MyClass>();
std::shared_ptr<MyClass> ptr2 = ptr1; // 拷贝,引用计数增至 2
std::cout << "Ref count: " << ptr1.use_count() << "\n"; // 输出 2
return 0; // 资源在最后一个 shared_ptr 销毁时释放
}
4.通过 std::unique_ptr 转移所有权
- 方式:将 std::unique_ptr 的所有权转移给 std::shared_ptr。
- 示例:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct MyClass {
~MyClass() { std::cout << "Destroyed\n"; }
};
int main() {
std::unique_ptr<MyClass> unique = std::make_unique<MyClass>();
std::shared_ptr<MyClass> shared = std::move(unique); // 转移所有权
std::cout << (unique == nullptr) << "\n"; // 输出 1(unique 已为空)
return 0;
} - 注意:转移后,unique_ptr 变为空。
2.指定删除器
在 C++ 中,std::shared_ptr 支持指定自定义删除器(deleter),以在资源释放时执行特定清理操作。自定义删除器在管理非标准内存资源(如文件句柄、自定义分配的内存等)或需要特殊清理逻辑时非常有用。以下是关于 std::shared_ptr 指定删除器的详细说明和示例。
1.使用函数指针作为删除器
1 |
|
- 输出:
1
2MyClass destroyed
Custom deleter called - 说明:删除器 customDeleter 在 shared_ptr 销毁时被调用,执行自定义清理逻辑。
2.使用 lambda 表达式作为删除器
1 |
|
- 输出:
1
2MyClass destroyed
Lambda deleter called - 优点:Lambda 表达式更灵活,适合临时定义删除逻辑。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct MyClass {
~MyClass() { std::cout << "MyClass destroyed\n"; }
};
int main() {
std::function<void(MyClass*)> deleter = [](MyClass* ptr) {
std::cout << "std::function deleter called\n";
delete ptr;
};
std::shared_ptr<MyClass> ptr(new MyClass(), deleter);
return 0;
} - 输出:
1
2MyClass destroyed
std::function deleter called - 说明:std::function 提供更大的灵活性,但有额外开销,适合复杂场景。