智能指针是 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