智能指针是 C++11 引入的重要特性,它们提供了自动内存管理功能,帮助避免内存泄漏、悬空指针等常见问题。智能指针是现代 C++ 编程的核心组成部分。
智能指针概述
为什么需要智能指针
#include <iostream>
// 传统指针的问题示例
void traditionalPointerProblems() {
std::cout << "=== 传统指针的问题 ===" << std::endl;
// 1. 内存泄漏
{
int* ptr = new int(42);
// 忘记 delete ptr; - 内存泄漏!
}
// 2. 重复删除
{
int* ptr = new int(100);
delete ptr;
// delete ptr; // 错误!重复删除
}
// 3. 悬空指针
{
int* ptr1 = new int(200);
int* ptr2 = ptr1;
delete ptr1;
// std::cout << *ptr2; // 错误!悬空指针
}
// 4. 异常安全问题
try {
int* ptr = new int(300);
// 如果这里抛出异常,ptr 不会被删除
throw std::runtime_error("Exception");
delete ptr; // 永远不会执行
} catch (...) {
std::cout << "捕获异常,但内存泄漏了" << std::endl;
}
}
// 智能指针解决方案预览
void smartPointerSolution() {
std::cout << "\n=== 智能指针解决方案 ===" << std::endl;
// 自动内存管理
{
std::unique_ptr<int> ptr = std::make_unique<int>(42);
// 自动删除,无需手动 delete
}
// 异常安全
try {
std::unique_ptr<int> ptr = std::make_unique<int>(300);
throw std::runtime_error("Exception");
// ptr 会自动清理,即使有异常
} catch (...) {
std::cout << "异常被捕获,但没有内存泄漏" << std::endl;
}
}
int main() {
traditionalPointerProblems();
smartPointerSolution();
return 0;
}
智能指针的基本原理
#include <iostream>
// 简化的智能指针实现示例
template<typename T>
class SimpleSmartPtr {
private:
T* ptr;
public:
// 构造函数
explicit SimpleSmartPtr(T* p = nullptr) : ptr(p) {
std::cout << "SmartPtr 构造,管理地址: " << ptr << std::endl;
}
// 析构函数:自动删除
~SimpleSmartPtr() {
std::cout << "SmartPtr 析构,删除地址: " << ptr << std::endl;
delete ptr;
}
// 禁止拷贝(简化版本)
SimpleSmartPtr(const SimpleSmartPtr&) = delete;
SimpleSmartPtr& operator=(const SimpleSmartPtr&) = delete;
// 解引用操作符
T& operator*() const {
return *ptr;
}
// 成员访问操作符
T* operator->() const {
return ptr;
}
// 获取原始指针
T* get() const {
return ptr;
}
// 检查是否为空
explicit operator bool() const {
return ptr != nullptr;
}
};
class TestClass {
public:
int value;
TestClass(int v) : value(v) {
std::cout << "TestClass 构造: " << value << std::endl;
}
~TestClass() {
std::cout << "TestClass 析构: " << value << std::endl;
}
void display() {
std::cout << "TestClass 值: " << value << std::endl;
}
};
int main() {
std::cout << "=== 智能指针原理演示 ===" << std::endl;
{
SimpleSmartPtr<TestClass> smart_ptr(new TestClass(42));
// 使用智能指针
smart_ptr->display();
(*smart_ptr).value = 100;
smart_ptr->display();
if (smart_ptr) {
std::cout << "智能指针有效" << std::endl;
}
// 作用域结束时自动清理
}
std::cout << "作用域结束,对象已自动清理" << std::endl;
return 0;
}
unique_ptr
unique_ptr 基础
#include <iostream>
#include <memory>
class Resource {
public:
int id;
Resource(int i) : id(i) {
std::cout << "Resource " << id << " 创建" << std::endl;
}
~Resource() {
std::cout << "Resource " << id << " 销毁" << std::endl;
}
void use() {
std::cout << "使用 Resource " << id << std::endl;
}
};
int main() {
std::cout << "=== unique_ptr 基础用法 ===" << std::endl;
// 1. 创建 unique_ptr
std::unique_ptr<Resource> ptr1(new Resource(1)); // 不推荐
auto ptr2 = std::make_unique<Resource>(2); // 推荐方式
// 2. 使用 unique_ptr
ptr1->use();
(*ptr2).use();
// 3. 检查是否为空
if (ptr1) {
std::cout << "ptr1 不为空" << std::endl;
}
// 4. 获取原始指针
Resource* raw_ptr = ptr1.get();
std::cout << "原始指针地址: " << raw_ptr << std::endl;
// 5. 释放所有权
std::unique_ptr<Resource> ptr3 = std::move(ptr1); // 移动所有权
if (!ptr1) {
std::cout << "ptr1 现在为空" << std::endl;
}
if (ptr3) {
std::cout << "ptr3 现在拥有资源" << std::endl;
ptr3->use();
}
// 6. 重置指针
ptr2.reset(); // 删除当前对象,指针变为空
ptr2.reset(new Resource(4)); // 删除当前对象,指向新对象
// 7. 释放所有权但不删除对象
Resource* released = ptr2.release();
std::cout << "释放的资源 ID: " << released->id << std::endl;
delete released; // 手动删除
std::cout << "函数结束,剩余对象将自动清理" << std::endl;
return 0;
}
unique_ptr 的移动语义
#include <iostream>
#include <memory>
#include <vector>
class ManagedResource {
public:
std::string name;
ManagedResource(const std::string& n) : name(n) {
std::cout << "创建资源: " << name << std::endl;
}
~ManagedResource() {
std::cout << "销毁资源: " << name << std::endl;
}
};
// 返回 unique_ptr
std::unique_ptr<ManagedResource> createResource(const std::string& name) {
return std::make_unique<ManagedResource>(name);
}
// 接受 unique_ptr 参数(转移所有权)
void consumeResource(std::unique_ptr<ManagedResource> resource) {
if (resource) {
std::cout << "消费资源: " << resource->name << std::endl;
}
// 函数结束时资源自动销毁
}
// 接受 unique_ptr 引用(不转移所有权)
void useResource(const std::unique_ptr<ManagedResource>& resource) {
if (resource) {
std::cout << "使用资源: " << resource->name << std::endl;
}
}
int main() {
std::cout << "=== unique_ptr 移动语义 ===" << std::endl;
// 1. 从函数返回 unique_ptr
auto resource1 = createResource("Resource1");
// 2. 移动构造
auto resource2 = std::move(resource1);
if (!resource1) {
std::cout << "resource1 已被移动,现在为空" << std::endl;
}
// 3. 传递给函数(转移所有权)
auto resource3 = createResource("Resource3");
useResource(resource3); // 不转移所有权
consumeResource(std::move(resource3)); // 转移所有权
if (!resource3) {
std::cout << "resource3 已被消费,现在为空" << std::endl;
}
// 4. 存储在容器中
std::vector<std::unique_ptr<ManagedResource>> resources;
resources.push_back(createResource("VectorResource1"));
resources.push_back(createResource("VectorResource2"));
resources.push_back(std::move(resource2)); // 移动到容器
std::cout << "容器中的资源:" << std::endl;
for (const auto& res : resources) {
if (res) {
std::cout << " " << res->name << std::endl;
}
}
std::cout << "函数结束,所有资源将自动清理" << std::endl;
return 0;
}
unique_ptr 与数组
#include <iostream>
#include <memory>
int main() {
std::cout << "=== unique_ptr 与数组 ===" << std::endl;
// 1. 管理动态数组
std::unique_ptr<int[]> arr1(new int[5]); // 注意 [] 语法
auto arr2 = std::make_unique<int[]>(5); // C++14 推荐方式
// 2. 初始化数组
for (int i = 0; i < 5; ++i) {
arr1[i] = i * 10;
arr2[i] = i * 20;
}
// 3. 使用数组
std::cout << "arr1: ";
for (int i = 0; i < 5; ++i) {
std::cout << arr1[i] << " ";
}
std::cout << std::endl;
std::cout << "arr2: ";
for (int i = 0; i < 5; ++i) {
std::cout << arr2[i] << " ";
}
std::cout << std::endl;
// 4. 获取原始指针
int* raw_arr = arr1.get();
std::cout << "通过原始指针访问: " << raw_arr[2] << std::endl;
// 5. 重置数组
arr1.reset(new int[3]{100, 200, 300}); // 重新分配
std::cout << "重置后的 arr1: ";
for (int i = 0; i < 3; ++i) {
std::cout << arr1[i] << " ";
}
std::cout << std::endl;
// 注意:unique_ptr<T[]> 会自动调用 delete[]
return 0;
}
shared_ptr
shared_ptr 基础
#include <iostream>
#include <memory>
class SharedResource {
public:
int value;
SharedResource(int v) : value(v) {
std::cout << "SharedResource " << value << " 创建" << std::endl;
}
~SharedResource() {
std::cout << "SharedResource " << value << " 销毁" << std::endl;
}
void display() const {
std::cout << "SharedResource 值: " << value << std::endl;
}
};
int main() {
std::cout << "=== shared_ptr 基础用法 ===" << std::endl;
// 1. 创建 shared_ptr
std::shared_ptr<SharedResource> ptr1 = std::make_shared<SharedResource>(42);
std::cout << "引用计数: " << ptr1.use_count() << std::endl; // 1
// 2. 拷贝 shared_ptr(增加引用计数)
{
std::shared_ptr<SharedResource> ptr2 = ptr1; // 拷贝构造
std::shared_ptr<SharedResource> ptr3;
ptr3 = ptr1; // 拷贝赋值
std::cout << "创建拷贝后引用计数: " << ptr1.use_count() << std::endl; // 3
ptr1->display();
ptr2->display();
ptr3->display();
// 修改对象
ptr2->value = 100;
ptr1->display(); // 所有指针都指向同一个对象
std::cout << "内部作用域结束前引用计数: " << ptr1.use_count() << std::endl;
} // ptr2 和 ptr3 销毁,引用计数减少
std::cout << "内部作用域结束后引用计数: " << ptr1.use_count() << std::endl; // 1
// 3. 重置指针
ptr1.reset(); // 引用计数变为 0,对象被销毁
if (!ptr1) {
std::cout << "ptr1 现在为空" << std::endl;
}
// 4. 创建新的 shared_ptr
auto ptr4 = std::make_shared<SharedResource>(200);
auto ptr5 = ptr4;
std::cout << "新对象引用计数: " << ptr4.use_count() << std::endl; // 2
return 0;
}
shared_ptr 的高级用法
#include <iostream>
#include <memory>
#include <vector>
class Node {
public:
int data;
std::vector<std::shared_ptr<Node>> children;
Node(int value) : data(value) {
std::cout << "Node " << data << " 创建" << st