为什么C++需要智能指针?`unique_ptr`和`shared_ptr`有何不同?
时间: 2025-06-30 15:21:19 浏览: 21
<think>我们首先回答为什么需要智能指针,然后解释unique_ptr和shared_ptr的不同之处。回答分为两部分:1.为什么需要智能指针?2. unique_ptr和shared_ptr的区别然后按照要求提出相关问题。</think>### 为什么C++需要智能指针?`unique_ptr`和`shared_ptr`有何不同?
#### 为什么需要智能指针?
**根本原因**:解决传统指针的**内存泄漏**和**资源管理**问题。
**具体问题**:
1. **内存泄漏**:手动`new/delete`不匹配导致
```cpp
void risky_function() {
int* ptr = new int[100];
if (error_occurred) return; // 内存泄漏!
delete[] ptr; // 可能永远不会执行
}
```
2. **异常安全问题**:异常抛出时delete可能被跳过
3. **所有权不明确**:多个指针指向同一资源时,谁负责释放?
4. **悬空指针**:资源释放后指针未置空
**解决方案**:智能指针通过**RAII(资源获取即初始化)** 技术:
- 在构造时获取资源
- 在析构时自动释放资源
- 提供明确的所有权语义
---
#### `unique_ptr` vs `shared_ptr`
| 特性 | `unique_ptr` | `shared_ptr` |
|---------------------|---------------------------------------|---------------------------------------|
| **所有权** | 独占所有权(不可复制) | 共享所有权(引用计数) |
| **复制行为** | 禁止复制,允许移动(`std::move`) | 允许复制(增加引用计数) |
| **性能开销** | 接近裸指针(零开销) | 有引用计数开销 |
| **适用场景** | 单一所有者场景 | 多个所有者共享资源场景 |
| **循环引用处理** | 不涉及 | 需配合`weak_ptr`避免内存泄漏 |
##### 代码示例
```cpp
#include <memory>
#include <iostream>
// unique_ptr 示例
void unique_ptr_demo() {
std::unique_ptr<int> uptr(new int(42));
// std::unique_ptr<int> uptr2 = uptr; // 错误!不可复制
std::unique_ptr<int> uptr2 = std::move(uptr); // 所有权转移
std::cout << *uptr2 << "\n"; // 输出42
} // 自动释放内存
// shared_ptr 示例
void shared_ptr_demo() {
std::shared_ptr<int> sptr1(new int(100));
{
std::shared_ptr<int> sptr2 = sptr1; // 复制,引用计数=2
std::cout << *sptr1 << " " << *sptr2 << "\n"; // 输出100 100
} // sptr2析构,引用计数=1
} // sptr1析构,引用计数=0,释放内存
// 循环引用示例(问题)
struct Node {
std::shared_ptr<Node> next;
~Node() { std::cout << "Node destroyed\n"; }
};
void cyclic_reference() {
auto node1 = std::make_shared<Node>();
auto node2 = std::make_shared<Node>();
node1->next = node2;
node2->next = node1; // 循环引用,内存泄漏!
} // 引用计数永远不为0,析构函数不会被调用
int main() {
unique_ptr_demo();
shared_ptr_demo();
cyclic_reference(); // 演示内存泄漏
return 0;
}
```
#### 关键区别详解
1. **`unique_ptr`**:
- 使用**移动语义**转移所有权
- 可作为函数返回值(编译器优化)
- 支持自定义删除器
```cpp
auto file_deleter = [](FILE* f) { fclose(f); };
std::unique_ptr<FILE, decltype(file_deleter)> file(fopen("test.txt", "r"), file_deleter);
```
2. **`shared_ptr`**:
- **控制块**存储引用计数(分配额外内存)
- 线程安全的引用计数(原子操作)
- 必须配合`weak_ptr`解决循环引用:
```cpp
struct SafeNode {
std::weak_ptr<SafeNode> next; // 使用weak_ptr打破循环
};
```
---
### 最佳实践建议
1. 优先使用`unique_ptr`(默认选择)
2. 需要共享所有权时才用`shared_ptr`
3. 工厂函数返回`unique_ptr`:
```cpp
std::unique_ptr<MyClass> create_object() {
return std::make_unique<MyClass>();
}
```
4. 使用`make_shared`替代`new`(减少内存分配次数)
阅读全文
相关推荐
















