C++ unique ptr 详解
外观
C++ unique_ptr 详解[编辑 | 编辑源代码]
unique_ptr 是 C++11 引入的一种智能指针,用于管理动态分配的内存资源。它遵循独占所有权(exclusive ownership)模型,确保同一时间只有一个 unique_ptr 可以指向特定的内存资源。当 unique_ptr 超出作用域或被销毁时,它会自动释放所管理的内存,从而有效防止内存泄漏。
基本概念[编辑 | 编辑源代码]
unique_ptr 是标准库头文件 <memory> 中定义的模板类,其核心特性包括:
- 独占所有权:同一时间只能有一个 unique_ptr 指向特定对象。
- 自动释放:当 unique_ptr 被销毁时,会自动调用 delete 或自定义删除器释放资源。
- 轻量高效:与裸指针相比,运行时开销几乎为零。
数学上,unique_ptr 可以表示为: 解析失败 (语法错误): {\displaystyle \text{unique\_ptr}(T) \rightarrow \text{owns}(p) \land \forall q \neq p, \neg\text{owns}(q) }
基本用法[编辑 | 编辑源代码]
创建 unique_ptr[编辑 | 编辑源代码]
#include <memory>
#include <iostream>
int main() {
// 方式1:使用构造函数
std::unique_ptr<int> ptr1(new int(42));
// 方式2:使用 std::make_unique (C++14引入)
auto ptr2 = std::make_unique<int>(100);
// 访问指针内容
std::cout << *ptr1 << ", " << *ptr2 << std::endl; // 输出: 42, 100
return 0;
}
所有权转移[编辑 | 编辑源代码]
unique_ptr 不能复制,但可以通过 std::move 转移所有权:
std::unique_ptr<int> source = std::make_unique<int>(200);
std::unique_ptr<int> destination;
// destination = source; // 错误!不能复制
destination = std::move(source); // 正确:所有权转移
if (!source) {
std::cout << "source 不再拥有所有权" << std::endl;
}
高级特性[编辑 | 编辑源代码]
自定义删除器[编辑 | 编辑源代码]
unique_ptr 允许指定自定义删除器来处理特殊资源:
struct FileDeleter {
void operator()(FILE* file) {
if (file) {
fclose(file);
std::cout << "文件已关闭" << std::endl;
}
}
};
int main() {
std::unique_ptr<FILE, FileDeleter> filePtr(fopen("test.txt", "w"));
if (filePtr) {
fprintf(filePtr.get(), "Hello, unique_ptr!");
}
// 文件会在 unique_ptr 销毁时自动关闭
return 0;
}
数组支持[编辑 | 编辑源代码]
unique_ptr 可以管理动态数组:
auto arrPtr = std::make_unique<int[]>(5); // 创建包含5个int的数组
for (int i = 0; i < 5; ++i) {
arrPtr[i] = i * 10;
}
实际应用案例[编辑 | 编辑源代码]
工厂模式中的应用[编辑 | 编辑源代码]
unique_ptr 非常适合用于工厂函数返回对象:
class Product {
public:
virtual ~Product() = default;
virtual void use() = 0;
};
class ConcreteProduct : public Product {
public:
void use() override {
std::cout << "使用具体产品" << std::endl;
}
};
std::unique_ptr<Product> createProduct() {
return std::make_unique<ConcreteProduct>();
}
int main() {
auto product = createProduct();
product->use();
return 0;
}
异常安全保证[编辑 | 编辑源代码]
unique_ptr 提供了强异常安全保证:
void processResource() {
auto res = std::make_unique<Resource>(); // 即使后面抛出异常,资源也会被释放
// 可能抛出异常的操作
res->doSomething();
// 不需要手动delete
}
与裸指针比较[编辑 | 编辑源代码]
最佳实践[编辑 | 编辑源代码]
1. 优先使用 std::make_unique 而非直接 new 2. 避免将 unique_ptr 转换为裸指针,除非必要 3. 使用 release() 谨慎,它会放弃所有权 4. 在 API 边界使用 unique_ptr 明确所有权转移
常见问题[编辑 | 编辑源代码]
能否在容器中使用 unique_ptr?[编辑 | 编辑源代码]
可以,但需要注意所有权语义:
std::vector<std::unique_ptr<int>> vec;
vec.push_back(std::make_unique<int>(1));
vec.push_back(std::make_unique<int>(2));
// 需要移动语义
auto ptr = std::make_unique<int>(3);
vec.push_back(std::move(ptr));
如何将 unique_ptr 用于多态?[编辑 | 编辑源代码]
unique_ptr 完全支持多态:
class Base { virtual ~Base() = default; };
class Derived : public Base {};
std::unique_ptr<Base> polyPtr = std::make_unique<Derived>();
性能考量[编辑 | 编辑源代码]
unique_ptr 的运行时开销与裸指针几乎相同:
- 构造/析构:与手动 new/delete 相当
- 访问操作:无额外开销
- 所有权转移:仅涉及指针复制
总结[编辑 | 编辑源代码]
unique_ptr 是 C++现代内存管理的核心工具之一,它:
- 提供自动内存管理,防止泄漏
- 明确表达独占所有权语义
- 几乎零开销
- 支持自定义删除器和数组
- 增强代码安全性和可读性
对于现代 C++ 开发,unique_ptr 应该成为动态内存分配的首选工具。