题目
编写程序,演示现代 C++ 独占所有权智能指针 std::unique_ptr。证明其作为原生裸指针的“零额外开销封装”(sizeof(unique_ptr) == sizeof(void*));展示其严禁拷贝(拷贝构造与赋值均被 delete)、仅允许通过 std::move 进行所有权转移(Ownership Transfer)的核心契约;演示自定义删除器(Custom Deleter)释放特殊系统资源的用法。
输入格式:无需外部输入。
输出格式:输出 unique_ptr 构造、所有权转移以及离开作用域自动析构堆对象的全流程。
数据范围与约定:独占所有权模型、移动语义交接、自定义删除器。
思路与算法
1. 独占所有权哲学
同一时刻,有且仅能有一个 std::unique_ptr 拥有目标堆对象的所有权。当该指针离开作用域时,自动调用底层 delete 释放资源。
2. 严禁拷贝与强制移动
尝试 p2 = p1; 会被编译器直接拦截;必须显式写 p2 = std::move(p1);,交接后 p1 被置为空指针 nullptr,所有权完全归属 p2。
3. make_unique 的安全规范
C++14 强烈推荐使用 std::make_unique<T>(args...) 替代裸 new,避免异常抛出时可能造成的内存泄漏并使代码表达更清晰。
完整程序
#include <iostream>
#include <memory>
#include <string>
class Resource {
public:
std::string name;
explicit Resource(std::string n) : name(std::move(n)) {
std::cout << " [构造 Resource] " << name << "\n";
}
~Resource() {
std::cout << " [析构 Resource] " << name << " (自动释放)\n";
}
void use() const {
std::cout << " [使用 Resource] " << name << " 正常工作中...\n";
}
};
int main() {
std::cout << "unique_ptr 实例本身占用栈空间: " << sizeof(std::unique_ptr<Resource>)
<< " 字节 (严格等于裸指针大小,零额外内存开销)\n\n";
// 1. 创建独占所有权指针
std::cout << "--- 1. 使用 std::make_unique 创建对象 ---\n";
std::unique_ptr<Resource> p1 = std::make_unique<Resource>("AlphaServer");
p1->use();
// 2. 所有权转移:移动语义
std::cout << "\n--- 2. 所有权转移: p2 = std::move(p1) ---\n";
std::unique_ptr<Resource> p2 = std::move(p1); // p1 放弃所有权
std::cout << "转移后 p1 是否为 nullptr: " << std::boolalpha << (p1 == nullptr) << "\n";
std::cout << "转移后 p2 是否有效: " << (p2 != nullptr) << "\n";
p2->use();
std::cout << "\n--- 3. 离开作用域,p2 自动析构管理的对象 ---\n";
return 0;
}运行示例
输出:
unique_ptr 实例本身占用栈空间: 8 字节 (严格等于裸指针大小,零额外内存开销)
--- 1. 使用 std::make_unique 创建对象 ---
[构造 Resource] AlphaServer
[使用 Resource] AlphaServer 正常工作中...
--- 2. 所有权转移: p2 = std::move(p1) ---
转移后 p1 是否为 nullptr: true
转移后 p2 是否有效: true
[使用 Resource] AlphaServer 正常工作中...
--- 3. 离开作用域,p2 自动析构管理的对象 ---
[析构 Resource] AlphaServer (自动释放)