DAY3

✅ Day 3 学习计划:智能指针与资源管理(C++11 重点)


🎯 今日目标:

  • 理解 unique_ptr / shared_ptr / weak_ptr 的使用和区别
  • 掌握智能指针的底层机制(引用计数、所有权)
  • 理解资源泄漏问题与解
  • 理解循环引用及其危害与解除方案

📘 一、系统知识学习

1. 什么是智能指针?

  • 智能指针是一种类模板,用来自动管理内存(RAII 原则实现)
  • 避免手动 delete,防止内存泄漏

2. unique_ptr

  • 独占式智能指针,不可复制,只能移动
  • 常用接口:std::make_unique<T>()
  • 应用场景:管理不共享的资源
std::unique_ptr<int> p1 = std::make_unique<int>(10);
// std::unique_ptr<int> p2 = p1; // 编译错误
std::unique_ptr<int> p2 = std::move(p1); // 转移所有权

3. shared_ptr

  • 引用计数式共享智能指针
  • 多个 shared_ptr 指向同一块内存,最后一个析构时释放
  • 常用接口:std::make_shared<T>()

4. weak_ptr

  • 弱引用,不增加引用计数
  • 用于解决 shared_ptr 之间的 循环引用问题
  • 可通过 lock() 获取临时有效的 shared_ptr

5. 智能指针底层机制

  • shared_ptr 内部包含引用计数控制块(use_count / weak_count)
  • use_count() 显示当前引用次数
  • 线程安全的引用计数实现(原子操作)

6. 循环引用的问题

struct A;
struct B;

struct A {
    std::shared_ptr<B> bptr;
};
struct B {
    std::shared_ptr<A> aptr; // 💥 循环引用,内存泄漏
};

// 正解:B 使用 weak_ptr
struct B2 {
    std::weak_ptr<A> aptr;  // ✅ 不增加引用计数
};

💻 二、实践任务:智能指针示例代码

建议任务:

  • 手写一个 shared_ptr 的引用计数模拟类
  • unique_ptr 管理一个动态数组资源
  • shared_ptr + weak_ptr 解决 A ↔ B 互持问题

❓ 三、面试题巩固

推荐今日 C++ 面试题:

  1. shared_ptr 的引用计数原理?
  2. shared_ptrunique_ptr 有哪些区别?
  3. 如何避免 shared_ptr 产生的循环引用?
  4. make_shared() 为什么比直接 new 更推荐?

🎯 四、设计模式学习任务:观察者模式(Observer)

场景:

  • 一对多依赖关系,一处变化通知多处
  • 典型:事件订阅 / 消息通知机制
#include <vector>
#include <iostream>
#include <memory>
#include <algorithm>
#include <mutex>

// 1. 抽象观察者接口
class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(int value) = 0;  // 更新接口
};

// 2. 具体观察者实现
class Logger : public Observer {
public:
    void update(int value) override {
        std::cout << "[Logger] Value changed to: " << value << std::endl;
    }
};

class AlertSystem : public Observer {
    const int threshold_ = 100;
public:
    void update(int value) override {
        if (value > threshold_) {
            std::cout << "⚠️ [ALERT] Value exceeded threshold: " << value 
                      << " > " << threshold_ << std::endl;
        }
    }
};

class GraphUpdater : public Observer {
public:
    void update(int value) override {
        std::cout << "📈 [Graph] Rendering new value: ";
        for (int i = 0; i < value % 10; ++i) std::cout << "■";
        std::cout << std::endl;
    }
};

// 3. 主题(被观察者)完整实现
class Subject {
    std::vector<Observer*> observers_;       // 观察者列表
    std::mutex mtx_;                         // 线程安全锁
    
public:
    virtual ~Subject() = default;
    
    // 添加观察者 (支持多态)
    void attach(Observer* obs) {
        std::lock_guard<std::mutex> lock(mtx_);
        observers_.push_back(obs);
    }
    
    // 移除观察者
    void detach(Observer* obs) {
        std::lock_guard<std::mutex> lock(mtx_);
        observers_.erase(
            std::remove(observers_.begin(), observers_.end(), obs),
            observers_.end()
        );
    }
    
    // 通知所有观察者 (推模型)
    void notify(int value) {
        std::lock_guard<std::mutex> lock(mtx_);
        for (auto obs : observers_) {
            obs->update(value);  // 多态调用
        }
    }
    
    // 提供拉模型接口(可选)
    virtual int getState() const = 0;
};

// 4. 具体主题实现 - 温度传感器
class TemperatureSensor : public Subject {
    int temperature_ = 0;
public:
    void setTemperature(int temp) {
        if (temp != temperature_) {
            temperature_ = temp;
            notify(temp);  // 状态变化时通知观察者
        }
    }
    
    int getState() const override { 
        return temperature_; 
    }
};

// 5. 智能指针管理扩展(避免悬挂指针)
class SafeSubject : public Subject {
    std::vector<std::weak_ptr<Observer>> weak_observers_;
    std::mutex mtx_;
public:
    void attach(std::shared_ptr<Observer> obs) {
        std::lock_guard<std::mutex> lock(mtx_);
        weak_observers_.push_back(obs);
    }

    void notify(int value) override {
        std::lock_guard<std::mutex> lock(mtx_);
        
        auto it = weak_observers_.begin();
        while (it != weak_observers_.end()) {
            if (auto shared_obs = it->lock()) {
                shared_obs->update(value);
                ++it;
            } else {
                it = weak_observers_.erase(it);  // 自动清除失效观察者
            }
        }
    }
};

// 6. 使用示例
int main() {
    // 创建主题(被观察者)
    TemperatureSensor sensor;
    
    // 创建观察者
    Logger logger;
    AlertSystem alert;
    GraphUpdater graph;
    
    // 注册观察者
    sensor.attach(&logger);
    sensor.attach(&alert);
    sensor.attach(&graph);
    
    // 模拟数据变化
    sensor.setTemperature(25);   // 正常更新
    sensor.setTemperature(120);  // 触发警报
    sensor.setTemperature(8);    // 图形更新
    
    // 移除观察者示例
    sensor.detach(&graph);
    std::cout << "\n--- Detached GraphUpdater ---\n";
    sensor.setTemperature(30);   // 不再显示图形
    
    // 智能指针版本示例
    SafeSubject safe_sensor;
    auto safe_logger = std::make_shared<Logger>();
    safe_sensor.attach(safe_logger);
    
    {
        auto temp_alert = std::make_shared<AlertSystem>();
        safe_sensor.attach(temp_alert);
        safe_sensor.notify(150);  // 两个观察者都生效
    } // temp_alert 离开作用域,自动解除注册
    
    std::cout << "\n--- AlertSystem destroyed ---\n";
    safe_sensor.notify(50);  // 仅logger生效(自动清理失效观察者)
}
  • 可升级为使用 std::function + 回调注册的现代写法

🔢 五、LeetCode 算法题推荐(指针+链表方向)

  1. LeetCode 141. 环形链表(快慢指针)
  2. LeetCode 160. 相交链表(长度差 + 双指针)

📝 六、今日总结

  • shared_ptrunique_ptr 的使用总结
  • weak_ptr 的使用场景代码
  • 面试题答案归纳
  • LeetCode 题解与思路
  • 观察者模式的结构图 + 代码实现(可类比 Qt 的信号槽机制)
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐