Skip to content

C++ 智能指针

概述

智能指针是C++11引入的重要特性,用于自动管理动态内存。智能指针通过RAII(Resource Acquisition Is Initialization)原则,在对象生命周期结束时自动释放资源,避免内存泄漏和悬空指针问题。

🔒 unique_ptr - 独占所有权

基础使用

cpp
#include <iostream>
#include <memory>
#include <vector>

class Resource {
private:
    std::string name_;
    
public:
    Resource(const std::string& name) : name_(name) {
        std::cout << "Resource创建: " << name_ << std::endl;
    }
    
    ~Resource() {
        std::cout << "Resource销毁: " << name_ << std::endl;
    }
    
    void doWork() const {
        std::cout << name_ << " 正在工作" << std::endl;
    }
    
    const std::string& getName() const { return name_; }
};

class UniquePointerDemo {
public:
    static void basicUsage() {
        std::cout << "=== unique_ptr基础使用 ===" << std::endl;
        
        // 创建unique_ptr
        std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>("资源1");
        
        // 访问对象
        ptr1->doWork();
        std::cout << "资源名称: " << (*ptr1).getName() << std::endl;
        
        // 检查是否为空
        if (ptr1) {
            std::cout << "ptr1不为空" << std::endl;
        }
        
        // 释放所有权
        Resource* raw_ptr = ptr1.release();
        std::cout << "释放后ptr1是否为空: " << (ptr1 == nullptr) << std::endl;
        
        // 手动删除(通常不推荐)
        delete raw_ptr;
        
        // 重新创建
        ptr1 = std::make_unique<Resource>("资源2");
        
        // reset - 重置指针
        ptr1.reset(new Resource("资源3"));
        
        // 自动销毁在作用域结束时
    }
    
    static void moveSemantics() {
        std::cout << "\n=== unique_ptr移动语义 ===" << std::endl;
        
        std::unique_ptr<Resource> ptr1 = std::make_unique<Resource>("移动资源");
        
        // 移动构造
        std::unique_ptr<Resource> ptr2 = std::move(ptr1);
        std::cout << "移动后ptr1是否为空: " << (ptr1 == nullptr) << std::endl;
        std::cout << "ptr2是否有效: " << (ptr2 != nullptr) << std::endl;
        
        // 移动赋值
        std::unique_ptr<Resource> ptr3;
        ptr3 = std::move(ptr2);
        
        if (ptr3) {
            ptr3->doWork();
        }
    }
    
    static void arraySupport() {
        std::cout << "\n=== unique_ptr数组支持 ===" << std::endl;
        
        // 数组形式的unique_ptr
        std::unique_ptr<int[]> arr = std::make_unique<int[]>(5);
        
        // 初始化数组
        for (int i = 0; i < 5; ++i) {
            arr[i] = i * i;
        }
        
        // 访问数组元素
        std::cout << "数组内容: ";
        for (int i = 0; i < 5; ++i) {
            std::cout << arr[i] << " ";
        }
        std::cout << std::endl;
        
        // 自动调用delete[]
    }
    
    static void customDeleter() {
        std::cout << "\n=== unique_ptr自定义删除器 ===" << std::endl;
        
        // 自定义删除器
        auto custom_deleter = [](Resource* r) {
            std::cout << "自定义删除器调用" << std::endl;
            delete r;
        };
        
        std::unique_ptr<Resource, decltype(custom_deleter)> 
            ptr(new Resource("自定义删除"), custom_deleter);
        
        ptr->doWork();
        
        // 作用域结束时调用自定义删除器
    }
};

🤝 shared_ptr - 共享所有权

引用计数管理

cpp
#include <iostream>
#include <memory>
#include <vector>

class SharedPointerDemo {
public:
    static void basicUsage() {
        std::cout << "=== shared_ptr基础使用 ===" << std::endl;
        
        // 创建shared_ptr
        std::shared_ptr<Resource> ptr1 = std::make_shared<Resource>("共享资源");
        std::cout << "引用计数: " << ptr1.use_count() << std::endl;
        
        {
            // 复制构造
            std::shared_ptr<Resource> ptr2 = ptr1;
            std::cout << "添加ptr2后引用计数: " << ptr1.use_count() << std::endl;
            
            // 赋值操作
            std::shared_ptr<Resource> ptr3;
            ptr3 = ptr1;
            std::cout << "添加ptr3后引用计数: " << ptr1.use_count() << std::endl;
            
            ptr2->doWork();
            
            // ptr2和ptr3在此处销毁
        }
        
        std::cout << "内部作用域结束后引用计数: " << ptr1.use_count() << std::endl;
        
        // ptr1在函数结束时销毁,引用计数变为0,对象被删除
    }
    
    static void containerUsage() {
        std::cout << "\n=== shared_ptr容器使用 ===" << std::endl;
        
        std::vector<std::shared_ptr<Resource>> resources;
        
        // 添加资源
        resources.push_back(std::make_shared<Resource>("容器资源1"));
        resources.push_back(std::make_shared<Resource>("容器资源2"));
        resources.push_back(std::make_shared<Resource>("容器资源3"));
        
        // 获取第一个资源的另一个引用
        std::shared_ptr<Resource> extra_ref = resources[0];
        std::cout << "第一个资源引用计数: " << extra_ref.use_count() << std::endl;
        
        // 使用资源
        for (const auto& res : resources) {
            res->doWork();
        }
        
        // 清空容器
        resources.clear();
        std::cout << "容器清空后extra_ref引用计数: " << extra_ref.use_count() << std::endl;
        
        // extra_ref在此处销毁
    }
    
    static void cyclicReference() {
        std::cout << "\n=== shared_ptr循环引用问题 ===" << std::endl;
        
        struct Node {
            int data;
            std::shared_ptr<Node> next;
            std::shared_ptr<Node> prev;  // 这会造成循环引用
            
            Node(int value) : data(value) {
                std::cout << "Node创建: " << data << std::endl;
            }
            
            ~Node() {
                std::cout << "Node销毁: " << data << std::endl;
            }
        };
        
        {
            auto node1 = std::make_shared<Node>(1);
            auto node2 = std::make_shared<Node>(2);
            
            // 创建循环引用
            node1->next = node2;
            node2->prev = node1;  // 循环引用!
            
            std::cout << "node1引用计数: " << node1.use_count() << std::endl;
            std::cout << "node2引用计数: " << node2.use_count() << std::endl;
            
            // 即使离开作用域,由于循环引用,对象也不会被销毁
        }
        
        std::cout << "作用域结束,但对象可能未销毁(内存泄漏)" << std::endl;
    }
};

🔗 weak_ptr - 弱引用

解决循环引用

cpp
#include <iostream>
#include <memory>

class WeakPointerDemo {
public:
    static void breakCyclicReference() {
        std::cout << "=== weak_ptr解决循环引用 ===" << std::endl;
        
        struct Node {
            int data;
            std::shared_ptr<Node> next;
            std::weak_ptr<Node> prev;  // 使用weak_ptr避免循环引用
            
            Node(int value) : data(value) {
                std::cout << "Node创建: " << data << std::endl;
            }
            
            ~Node() {
                std::cout << "Node销毁: " << data << std::endl;
            }
            
            void printPrev() {
                if (auto prev_shared = prev.lock()) {  // 尝试获取shared_ptr
                    std::cout << "前一个节点: " << prev_shared->data << std::endl;
                } else {
                    std::cout << "前一个节点已被销毁或不存在" << std::endl;
                }
            }
        };
        
        {
            auto node1 = std::make_shared<Node>(1);
            auto node2 = std::make_shared<Node>(2);
            
            // 设置关系
            node1->next = node2;
            node2->prev = node1;  // weak_ptr,不影响引用计数
            
            std::cout << "node1引用计数: " << node1.use_count() << std::endl;
            std::cout << "node2引用计数: " << node2.use_count() << std::endl;
            
            node2->printPrev();
            
            // 正常销毁
        }
        
        std::cout << "作用域结束,对象正常销毁" << std::endl;
    }
    
    static void observerPattern() {
        std::cout << "\n=== weak_ptr观察者模式 ===" << std::endl;
        
        class Subject;
        
        class Observer {
        private:
            std::weak_ptr<Subject> subject_;
            std::string name_;
            
        public:
            Observer(const std::string& name) : name_(name) {}
            
            void setSubject(std::weak_ptr<Subject> subject) {
                subject_ = subject;
            }
            
            void notify() {
                if (auto subject = subject_.lock()) {
                    std::cout << name_ << " 收到通知,主题仍然存在" << std::endl;
                } else {
                    std::cout << name_ << " 收到通知,但主题已被销毁" << std::endl;
                }
            }
        };
        
        class Subject {
        private:
            std::vector<std::weak_ptr<Observer>> observers_;
            
        public:
            Subject() {
                std::cout << "Subject创建" << std::endl;
            }
            
            ~Subject() {
                std::cout << "Subject销毁" << std::endl;
            }
            
            void addObserver(std::weak_ptr<Observer> observer) {
                observers_.push_back(observer);
            }
            
            void notifyAll() {
                for (auto& weak_obs : observers_) {
                    if (auto obs = weak_obs.lock()) {
                        obs->notify();
                    }
                }
            }
        };
        
        auto subject = std::make_shared<Subject>();
        auto observer1 = std::make_shared<Observer>("观察者1");
        auto observer2 = std::make_shared<Observer>("观察者2");
        
        // 设置观察关系
        observer1->setSubject(subject);
        observer2->setSubject(subject);
        subject->addObserver(observer1);
        subject->addObserver(observer2);
        
        // 通知
        subject->notifyAll();
        
        // 销毁一个观察者
        observer2.reset();
        
        // 再次通知
        subject->notifyAll();
    }
    
    static void weakPtrOperations() {
        std::cout << "\n=== weak_ptr操作 ===" << std::endl;
        
        std::shared_ptr<Resource> shared = std::make_shared<Resource>("weak测试");
        std::weak_ptr<Resource> weak = shared;
        
        std::cout << "shared引用计数: " << shared.use_count() << std::endl;
        std::cout << "weak是否过期: " << weak.expired() << std::endl;
        
        // 通过weak_ptr访问对象
        if (auto locked = weak.lock()) {
            locked->doWork();
            std::cout << "通过weak_ptr成功访问" << std::endl;
        }
        
        // 销毁shared_ptr
        shared.reset();
        
        std::cout << "shared销毁后,weak是否过期: " << weak.expired() << std::endl;
        
        // 尝试访问已销毁的对象
        if (auto locked = weak.lock()) {
            locked->doWork();
        } else {
            std::cout << "对象已销毁,无法通过weak_ptr访问" << std::endl;
        }
    }
};

🛠️ 智能指针实践

工厂模式和RAII

cpp
#include <iostream>
#include <memory>
#include <map>
#include <functional>

class SmartPointerPatterns {
public:
    // 工厂模式
    class ShapeFactory {
    public:
        enum class ShapeType { CIRCLE, RECTANGLE, TRIANGLE };
        
        static std::unique_ptr<Shape> createShape(ShapeType type) {
            switch (type) {
                case ShapeType::CIRCLE:
                    return std::make_unique<Circle>();
                case ShapeType::RECTANGLE:
                    return std::make_unique<Rectangle>();
                case ShapeType::TRIANGLE:
                    return std::make_unique<Triangle>();
                default:
                    return nullptr;
            }
        }
    };
    
    // RAII资源管理
    class FileManager {
    private:
        std::unique_ptr<FILE, std::function<void(FILE*)>> file_;
        
    public:
        FileManager(const std::string& filename, const std::string& mode) {
            FILE* f = fopen(filename.c_str(), mode.c_str());
            if (!f) {
                throw std::runtime_error("无法打开文件: " + filename);
            }
            
            file_ = std::unique_ptr<FILE, std::function<void(FILE*)>>(
                f, [](FILE* fp) {
                    if (fp) {
                        std::cout << "关闭文件" << std::endl;
                        fclose(fp);
                    }
                }
            );
        }
        
        void write(const std::string& data) {
            if (file_) {
                fprintf(file_.get(), "%s", data.c_str());
                fflush(file_.get());
            }
        }
        
        bool isOpen() const {
            return file_ != nullptr;
        }
    };
    
    // 缓存系统
    class Cache {
    private:
        std::map<std::string, std::weak_ptr<Resource>> cache_;
        
    public:
        std::shared_ptr<Resource> getResource(const std::string& name) {
            auto it = cache_.find(name);
            if (it != cache_.end()) {
                if (auto resource = it->second.lock()) {
                    std::cout << "从缓存获取: " << name << std::endl;
                    return resource;
                } else {
                    // 资源已被销毁,从缓存中移除
                    cache_.erase(it);
                }
            }
            
            // 创建新资源
            std::cout << "创建新资源: " << name << std::endl;
            auto resource = std::make_shared<Resource>(name);
            cache_[name] = resource;
            return resource;
        }
        
        void cleanup() {
            for (auto it = cache_.begin(); it != cache_.end();) {
                if (it->second.expired()) {
                    it = cache_.erase(it);
                } else {
                    ++it;
                }
            }
        }
        
        size_t size() const {
            return cache_.size();
        }
    };
    
    static void demonstratePatterns() {
        std::cout << "=== 智能指针设计模式 ===" << std::endl;
        
        // 工厂模式
        auto circle = ShapeFactory::createShape(ShapeFactory::ShapeType::CIRCLE);
        if (circle) {
            circle->draw();
        }
        
        // RAII文件管理
        try {
            FileManager fm("test.txt", "w");
            fm.write("Hello, RAII!\n");
            std::cout << "文件写入成功" << std::endl;
            // 文件在FileManager销毁时自动关闭
        } catch (const std::exception& e) {
            std::cout << "文件操作错误: " << e.what() << std::endl;
        }
        
        // 缓存系统
        Cache cache;
        
        {
            auto res1 = cache.getResource("资源A");
            auto res2 = cache.getResource("资源B");
            auto res3 = cache.getResource("资源A");  // 从缓存获取
            
            std::cout << "缓存大小: " << cache.size() << std::endl;
            
            res1->doWork();
            res2->doWork();
        }
        
        // 清理过期的弱引用
        cache.cleanup();
        std::cout << "清理后缓存大小: " << cache.size() << std::endl;
    }
};

// 辅助类定义
class Shape {
public:
    virtual ~Shape() = default;
    virtual void draw() const = 0;
};

class Circle : public Shape {
public:
    void draw() const override {
        std::cout << "绘制圆形" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() const override {
        std::cout << "绘制矩形" << std::endl;
    }
};

class Triangle : public Shape {
public:
    void draw() const override {
        std::cout << "绘制三角形" << std::endl;
    }
};

int main() {
    UniquePointerDemo::basicUsage();
    UniquePointerDemo::moveSemantics();
    UniquePointerDemo::arraySupport();
    UniquePointerDemo::customDeleter();
    
    SharedPointerDemo::basicUsage();
    SharedPointerDemo::containerUsage();
    SharedPointerDemo::cyclicReference();
    
    WeakPointerDemo::breakCyclicReference();
    WeakPointerDemo::observerPattern();
    WeakPointerDemo::weakPtrOperations();
    
    SmartPointerPatterns::demonstratePatterns();
    
    return 0;
}

总结

智能指针是现代C++内存管理的核心工具,提供了安全高效的资源管理:

智能指针类型

  • unique_ptr: 独占所有权,不可复制,可移动
  • shared_ptr: 共享所有权,引用计数管理
  • weak_ptr: 弱引用,解决循环引用问题

使用场景

指针类型适用场景性能特点
unique_ptr独占资源零开销
shared_ptr共享资源原子操作开销
weak_ptr观察者模式最小开销

最佳实践

  • 优先使用make_uniquemake_shared
  • 避免使用原始指针管理资源
  • 使用weak_ptr打破循环引用
  • 利用RAII原则自动管理资源
  • 选择合适的智能指针类型

设计原则

  • RAII: 资源获取即初始化
  • 异常安全: 智能指针提供强异常安全保证
  • 清晰所有权: 明确资源所有权语义
  • 自动管理: 避免手动内存管理错误

智能指针消除了大部分内存管理错误,是现代C++不可或缺的特性。

本站内容仅供学习和研究使用。