最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一文詳解C++中的智能指針避坑指南

 更新時(shí)間:2025年12月03日 08:30:26   作者:碼事漫談  
你以為將new替換為make_shared就萬(wàn)事大吉嗎,真相是智能指針的陷阱比手動(dòng)管理更隱蔽更危險(xiǎn),本文將深入剖析循環(huán)引用,性能陷阱和線程安全,希望對(duì)大家有所幫助

你以為將new替換為make_shared就萬(wàn)事大吉?真相是,智能指針的陷阱比手動(dòng)管理更隱蔽、更危險(xiǎn)。本文將深入剖析循環(huán)引用、性能陷阱、線程安全這三大「暗礁」,讓你從「自以為會(huì)」到「真正精通」。

一個(gè)經(jīng)典的崩潰代碼

如下代碼展露了智能指針中的循環(huán)引用問(wèn)題。

// 這就是那個(gè)導(dǎo)致崩潰的簡(jiǎn)化版代碼
class UserProfile {
    std::shared_ptr<UserProfile> recommend_to;  // 推薦給誰(shuí)
    // ... 其他數(shù)據(jù)
};

void create_recommendation_cycle() {
    auto user1 = std::make_shared<UserProfile>();
    auto user2 = std::make_shared<UserProfile>();
    
    user1->recommend_to = user2;  // user1推薦user2
    user2->recommend_to = user1;  // user2又推薦user1
    
    // 離開(kāi)作用域后,引用計(jì)數(shù)永遠(yuǎn)不會(huì)歸零!
    // 內(nèi)存泄漏,最終OOM(內(nèi)存耗盡)
}

這就是智能指針最諷刺的地方:你為了避免內(nèi)存泄漏而使用它,結(jié)果它卻導(dǎo)致了更隱蔽的內(nèi)存泄漏。

錯(cuò)誤一:循環(huán)引用——智能指針的「鬼打墻」

1.1 循環(huán)引用的典型場(chǎng)景

// 場(chǎng)景1:雙向關(guān)聯(lián)(父子節(jié)點(diǎn))
class TreeNode {
public:
    std::shared_ptr<TreeNode> parent;
    std::vector<std::shared_ptr<TreeNode>> children;
    
    void add_child(std::shared_ptr<TreeNode> child) {
        children.push_back(child);
        child->parent = shared_from_this();  // 致命錯(cuò)誤!
    }
};

// 場(chǎng)景2:觀察者模式中的相互持有
class Observer;
class Subject {
    std::vector<std::shared_ptr<Observer>> observers;
};

class Observer {
    std::shared_ptr<Subject> subject;  // 互相持有!
};

// 場(chǎng)景3:緩存系統(tǒng)中的自引用
class CacheEntry {
    std::shared_ptr<CacheEntry> next_in_lru;  // LRU鏈表
    std::shared_ptr<CacheEntry> prev_in_lru;
};

1.2 解決方案:weak_ptr的正確使用

// 正確方案1:使用weak_ptr打破循環(huán)
class TreeNode {
private:
    std::weak_ptr<TreeNode> parent_;  // 關(guān)鍵改變!
    std::vector<std::shared_ptr<TreeNode>> children_;
    
public:
    void set_parent(std::shared_ptr<TreeNode> parent) {
        parent_ = parent;  // weak_ptr不會(huì)增加引用計(jì)數(shù)
    }
    
    std::shared_ptr<TreeNode> get_parent() const {
        return parent_.lock();  // 嘗試提升為shared_ptr
    }
    
    void add_child(std::shared_ptr<TreeNode> child) {
        children_.push_back(child);
        child->set_parent(shared_from_this());
    }
};

// 正確方案2:明確所有權(quán)關(guān)系
class Document {
    // 文檔擁有頁(yè)面(獨(dú)占所有權(quán))
    std::vector<std::unique_ptr<Page>> pages_;
    
    // 頁(yè)面可以引用文檔,但不擁有
    class Page {
        Document* document_;  // 原始指針!安全嗎?
        // 這里的關(guān)鍵:生命周期由Document管理
    };
};

1.3 深度分析:weak_ptr的工作原理

// weak_ptr內(nèi)部機(jī)制模擬
template<typename T>
class WeakPtr {
private:
    T* ptr_;                    // 指向?qū)嶋H對(duì)象
    ControlBlock* control_block_;  // 與shared_ptr共享的控制塊
    
public:
    // lock()方法的實(shí)現(xiàn)
    std::shared_ptr<T> lock() const noexcept {
        if(control_block_ && control_block_->ref_count > 0) {
            // 對(duì)象還活著,創(chuàng)建新的shared_ptr
            return std::shared_ptr<T>(*this);
        }
        return std::shared_ptr<T>();  // 返回空shared_ptr
    }
    
    // 控制塊結(jié)構(gòu)
    struct ControlBlock {
        std::atomic<size_t> ref_count{1};     // 強(qiáng)引用計(jì)數(shù)
        std::atomic<size_t> weak_count{1};    // 弱引用計(jì)數(shù)
        T* object_ptr{nullptr};
        
        ~ControlBlock() {
            if(ref_count == 0) {
                delete object_ptr;  // 只有強(qiáng)引用為0時(shí)才刪除對(duì)象
            }
            // weak_count為0時(shí)刪除控制塊本身
        }
    };
};

關(guān)鍵點(diǎn)

  • weak_ptr不增加強(qiáng)引用計(jì)數(shù),只增加弱引用計(jì)數(shù)
  • 對(duì)象銷(xiāo)毀的條件:強(qiáng)引用計(jì)數(shù) == 0
  • 控制塊銷(xiāo)毀的條件:強(qiáng)引用計(jì)數(shù) == 0 弱引用計(jì)數(shù) == 0

1.4 循環(huán)引用檢測(cè)工具

// 運(yùn)行時(shí)檢測(cè)工具
class CyclicReferenceDetector {
public:
    template<typename T>
    static bool has_cycle(const std::shared_ptr<T>& start) {
        std::unordered_set<void*> visited;
        return detect_cycle(start, visited);
    }
    
private:
    template<typename T>
    static bool detect_cycle(const std::shared_ptr<T>& current,
                            std::unordered_set<void*>& visited) {
        if(!current) return false;
        
        void* address = current.get();
        if(visited.count(address)) {
            std::cerr << "Cycle detected at: " << typeid(T).name() 
                     << " [" << address << "]" << std::endl;
            return true;
        }
        
        visited.insert(address);
        
        // 使用反射或手動(dòng)注冊(cè)來(lái)遍歷成員
        // 這里簡(jiǎn)化,實(shí)際需要更復(fù)雜的機(jī)制
        return false;
    }
};

// 使用示例
void check_for_cycles() {
    auto obj = std::make_shared<TreeNode>();
    // ... 構(gòu)建可能循環(huán)的結(jié)構(gòu)
    
    if(CyclicReferenceDetector::has_cycle(obj)) {
        std::cerr << "WARNING: Memory leak due to cyclic reference!" << std::endl;
    }
}

錯(cuò)誤二:性能陷阱——你以為的「零成本」抽象

2.1 shared_ptr的隱藏成本

// 性能測(cè)試:shared_ptr vs 原始指針
void benchmark_shared_ptr() {
    constexpr size_t ITERATIONS = 1000000;
    std::vector<std::shared_ptr<Data>> shared_ptrs;
    std::vector<Data*> raw_ptrs;
    
    // 創(chuàng)建開(kāi)銷(xiāo)
    auto start = std::chrono::high_resolution_clock::now();
    for(size_t i = 0; i < ITERATIONS; ++i) {
        shared_ptrs.push_back(std::make_shared<Data>(i));
    }
    auto shared_create = std::chrono::high_resolution_clock::now() - start;
    
    start = std::chrono::high_resolution_clock::now();
    for(size_t i = 0; i < ITERATIONS; ++i) {
        raw_ptrs.push_back(new Data(i));
    }
    auto raw_create = std::chrono::high_resolution_clock::now() - start;
    
    std::cout << "創(chuàng)建開(kāi)銷(xiāo):\n"
              << "  shared_ptr: " 
              << std::chrono::duration<double, std::milli>(shared_create).count()
              << "ms\n"
              << "  原始指針: "
              << std::chrono::duration<double, std::milli>(raw_create).count()
              << "ms\n";
    
    // 拷貝開(kāi)銷(xiāo)
    start = std::chrono::high_resolution_clock::now();
    for(size_t i = 0; i < ITERATIONS; ++i) {
        auto copy = shared_ptrs[i];  // 原子操作!
    }
    auto shared_copy = std::chrono::high_resolution_clock::now() - start;
    
    std::cout << "拷貝開(kāi)銷(xiāo):\n"
              << "  shared_ptr: "
              << std::chrono::duration<double, std::milli>(shared_copy).count()
              << "ms (每個(gè)拷貝約"
              << std::chrono::duration<double, std::nano>(shared_copy).count()/ITERATIONS
              << "ns)\n";
}

性能開(kāi)銷(xiāo)來(lái)源

  • 控制塊分配:額外的一次內(nèi)存分配(除非用make_shared
  • 原子操作:引用計(jì)數(shù)的增減需要原子操作,影響多核性能
  • 緩存不友好:對(duì)象和控制塊可能不在同一緩存行
  • 虛函數(shù)開(kāi)銷(xiāo):自定義刪除器和分配器可能引入間接調(diào)用

2.2 make_shared vs shared_ptr構(gòu)造函數(shù)

// 關(guān)鍵區(qū)別:內(nèi)存布局
class LargeObject {
    char data[1024];  // 1KB數(shù)據(jù)
};

void memory_layout_demo() {
    // 方式1:兩次內(nèi)存分配
    std::shared_ptr<LargeObject> p1(new LargeObject);
    // 堆布局:[控制塊] ... [LargeObject]
    // 兩次分配,可能內(nèi)存碎片
    
    // 方式2:一次內(nèi)存分配(推薦)
    auto p2 = std::make_shared<LargeObject>();
    // 堆布局:[控制塊 + LargeObject]
    // 單次分配,更好的局部性
    
    // 但注意:weak_ptr會(huì)阻止整個(gè)內(nèi)存塊釋放
    std::weak_ptr<LargeObject> weak = p2;
    p2.reset();  // LargeObject析構(gòu),但內(nèi)存直到weak銷(xiāo)毀才釋放
}

2.3 性能優(yōu)化策略

// 策略1:優(yōu)先使用unique_ptr
class ConnectionPool {
private:
    // 池?fù)碛兴羞B接
    std::vector<std::unique_ptr<Connection>> connections_;
    
    // 借出時(shí)返回原始指針或引用
    Connection* borrow_connection() {
        return connections_[next_available_].get();
    }
    
    // unique_ptr沒(méi)有引用計(jì)數(shù)開(kāi)銷(xiāo)
    // 所有權(quán)清晰,零額外成本
};

// 策略2:傳遞const引用而不是拷貝shared_ptr
void process_data_bad(const std::shared_ptr<Data>& data) {
    // 這里看似沒(méi)有拷貝,但可能在其他地方有
    auto local_copy = data;  // 原子遞增!
    // ...
}

void process_data_good(const Data& data) {  // 直接傳遞引用
    // 沒(méi)有引用計(jì)數(shù)操作
    // 調(diào)用者需保證data的生命周期
}

// 策略3:局部使用shared_ptr,長(zhǎng)期使用weak_ptr
class SessionManager {
private:
    std::unordered_map<SessionId, std::weak_ptr<Session>> sessions_;
    
public:
    std::shared_ptr<Session> get_session(SessionId id) {
        if(auto it = sessions_.find(id); it != sessions_.end()) {
            if(auto session = it->second.lock()) {
                return session;  // 會(huì)話還活著
            }
            sessions_.erase(it);  // 會(huì)話已過(guò)期,清理
        }
        return nullptr;
    }
    
    void register_session(SessionId id, std::shared_ptr<Session> session) {
        sessions_[id] = session;  // 存儲(chǔ)weak_ptr,不阻止銷(xiāo)毀
    }
};

2.4 原子操作的性能影響

// shared_ptr引用計(jì)數(shù)的原子操作(簡(jiǎn)化版)
template<typename T>
class SharedPtr {
    T* ptr;
    std::atomic<long>* ref_count;  // 原子類(lèi)型
    
public:
    SharedPtr(const SharedPtr& other) : ptr(other.ptr), ref_count(other.ref_count) {
        // 內(nèi)存屏障!影響多核性能
        ref_count->fetch_add(1, std::memory_order_relaxed);
    }
    
    ~SharedPtr() {
        if(ref_count->fetch_sub(1, std::memory_order_acq_rel) == 1) {
            delete ptr;
            delete ref_count;
        }
    }
};

// 性能對(duì)比:?jiǎn)尉€程 vs 多線程
void atomic_overhead_demo() {
    std::atomic<int> atomic_counter{0};
    int non_atomic_counter = 0;
    
    constexpr int ITERATIONS = 10000000;
    
    // 單線程性能
    auto start = std::chrono::high_resolution_clock::now();
    for(int i = 0; i < ITERATIONS; ++i) {
        atomic_counter.fetch_add(1, std::memory_order_relaxed);
    }
    auto atomic_time = std::chrono::high_resolution_clock::now() - start;
    
    start = std::chrono::high_resolution_clock::now();
    for(int i = 0; i < ITERATIONS; ++i) {
        ++non_atomic_counter;
    }
    auto non_atomic_time = std::chrono::high_resolution_clock::now() - start;
    
    std::cout << "原子操作開(kāi)銷(xiāo): "
              << std::chrono::duration<double, std::milli>(atomic_time).count() / 
                 std::chrono::duration<double, std::milli>(non_atomic_time).count()
              << "倍\n";
}

錯(cuò)誤三:線程安全——最危險(xiǎn)的幻覺(jué)

3.1 shared_ptr的線程安全層級(jí)

// shared_ptr的線程安全是分層的:
class ThreadSafetyLevels {
    // 級(jí)別1:控制塊線程安全(標(biāo)準(zhǔn)保證)
    //   - 引用計(jì)數(shù)的增減是原子的
    //   - 不同的shared_ptr實(shí)例可以被不同線程安全地析構(gòu)
    
    // 級(jí)別2:指向的數(shù)據(jù)線程不安全!
    //   - shared_ptr不保證其管理的對(duì)象的線程安全
    //   - 多個(gè)線程同時(shí)讀寫(xiě)同一個(gè)對(duì)象需要外部同步
    
    // 級(jí)別3:同一個(gè)shared_ptr實(shí)例的讀寫(xiě)不安全!
    //   - 同一個(gè)shared_ptr對(duì)象被多個(gè)線程讀寫(xiě)需要同步
};

// 證明:shared_ptr內(nèi)部不保護(hù)對(duì)象
void concurrent_access_problem() {
    auto shared_data = std::make_shared<std::vector<int>>();
    
    // 線程1:修改數(shù)據(jù)
    std::thread t1([&shared_data]() {
        for(int i = 0; i < 1000; ++i) {
            shared_data->push_back(i);  // 競(jìng)態(tài)條件!
        }
    });
    
    // 線程2:同時(shí)讀取
    std::thread t2([&shared_data]() {
        for(int i = 0; i < 1000; ++i) {
            if(!shared_data->empty()) {
                int value = shared_data->back();  // 可能讀取到無(wú)效數(shù)據(jù)!
            }
        }
    });
    
    t1.join();
    t2.join();
    // 結(jié)果:未定義行為!可能崩潰或數(shù)據(jù)損壞
}

3.2 典型線程安全問(wèn)題

// 問(wèn)題1:錯(cuò)誤的「線程安全」假設(shè)
class ThreadUnsafeCache {
    std::unordered_map<std::string, std::shared_ptr<Data>> cache_;
    std::mutex mutex_;
    
public:
    std::shared_ptr<Data> get(const std::string& key) {
        std::lock_guard<std::mutex> lock(mutex_);
        if(auto it = cache_.find(key); it != cache_.end()) {
            return it->second;  // 看似安全...
        }
        return nullptr;
    }
    
    // 問(wèn)題:返回的shared_ptr可能被多個(gè)線程同時(shí)持有
    // 它們可以同時(shí)修改Data,而Data沒(méi)有內(nèi)置的線程保護(hù)!
};

// 問(wèn)題2:shared_ptr的原子操作誤解
void atomic_shared_ptr_misconception() {
    std::shared_ptr<int> p = std::make_shared<int>(42);
    
    std::thread t1([&p]() {
        auto local_copy = p;  // 引用計(jì)數(shù)原子遞增
        // 但p.reset()可能同時(shí)發(fā)生!
    });
    
    std::thread t2([&p]() {
        p.reset(new int(100));  // 修改p本身需要同步!
    });
    
    t1.join();
    t2.join();
    // 這里有兩個(gè)獨(dú)立的數(shù)據(jù)競(jìng)爭(zhēng):
    // 1. 對(duì)p本身的修改(shared_ptr對(duì)象)
    // 2. 對(duì)新舊int對(duì)象的訪問(wèn)
};

3.3 線程安全智能指針實(shí)現(xiàn)

// 方案1:使用atomic_shared_ptr(C++20)
#include <atomic>
#include <memory>

void cpp20_atomic_shared_ptr() {
    std::atomic<std::shared_ptr<int>> atomic_ptr;
    
    // 線程安全地存儲(chǔ)
    std::thread writer([&atomic_ptr]() {
        atomic_ptr.store(std::make_shared<int>(42));
    });
    
    // 線程安全地加載
    std::thread reader([&atomic_ptr]() {
        std::shared_ptr<int> local = atomic_ptr.load();
        if(local) {
            // 安全讀取local指向的內(nèi)容
            // 但多個(gè)reader可能同時(shí)讀取,內(nèi)容本身需要保護(hù)
        }
    });
    
    writer.join();
    reader.join();
}

// 方案2:手動(dòng)實(shí)現(xiàn)帶鎖的智能指針
template<typename T>
class ThreadSafeSharedPtr {
private:
    struct ControlBlock {
        T* ptr;
        std::atomic<size_t> ref_count;
        std::mutex data_mutex;  // 保護(hù)對(duì)象本身
        
        // 自定義刪除器,確保安全銷(xiāo)毀
        void safe_delete() {
            std::lock_guard<std::mutex> lock(data_mutex);
            delete ptr;
            ptr = nullptr;
        }
    };
    
    ControlBlock* cb_;
    
public:
    // 提供線程安全的訪問(wèn)接口
    template<typename Func>
    auto with_lock(Func&& func) {
        std::lock_guard<std::mutex> lock(cb_->data_mutex);
        return std::forward<Func>(func)(*cb_->ptr);
    }
    
    // 線程安全的reset
    void reset(T* new_ptr = nullptr) {
        if(cb_ && cb_->ref_count.fetch_sub(1) == 1) {
            cb_->safe_delete();
            delete cb_;
        }
        if(new_ptr) {
            cb_ = new ControlBlock{new_ptr, 1};
        } else {
            cb_ = nullptr;
        }
    }
};

3.4 多線程環(huán)境最佳實(shí)踐

// 最佳實(shí)踐1:使用不可變數(shù)據(jù)
class ImmutableData {
private:
    const std::vector<int> data_;  // 構(gòu)造后不可變
    
public:
    // 線程安全:多個(gè)線程可以同時(shí)讀取
    int get(size_t index) const {
        return data_.at(index);
    }
    
    // 創(chuàng)建新版本而不是修改
    std::shared_ptr<ImmutableData> with_addition(int value) const {
        auto new_data = std::make_shared<ImmutableData>(*this);
        // 注意:這里需要實(shí)際的不可變實(shí)現(xiàn)
        return new_data;
    }
};

// 最佳實(shí)踐2:明確的所有權(quán)傳遞
class ThreadSafeMessageQueue {
private:
    struct Message {
        std::unique_ptr<Data> data;  // 獨(dú)占所有權(quán)
        // unique_ptr明確表示:只有一個(gè)線程擁有
    };
    
    std::queue<Message> queue_;
    std::mutex queue_mutex_;
    std::condition_variable cv_;
    
public:
    // 生產(chǎn)者:轉(zhuǎn)移所有權(quán)到隊(duì)列
    void push(std::unique_ptr<Data> data) {
        {
            std::lock_guard<std::mutex> lock(queue_mutex_);
            queue_.push(Message{std::move(data)});
        }
        cv_.notify_one();
    }
    
    // 消費(fèi)者:從隊(duì)列獲取所有權(quán)
    std::unique_ptr<Data> pop() {
        std::unique_lock<std::mutex> lock(queue_mutex_);
        cv_.wait(lock, [this]{ return !queue_.empty(); });
        
        Message msg = std::move(queue_.front());
        queue_.pop();
        
        return std::move(msg.data);  // 所有權(quán)轉(zhuǎn)移給消費(fèi)者
    }
};

// 最佳實(shí)踐3:使用shared_ptr的別名構(gòu)造函數(shù)
class ThreadSafeObserver {
private:
    std::shared_ptr<std::mutex> mutex_;  // 共享的mutex
    std::shared_ptr<Data> data_;          // 共享的數(shù)據(jù)
    
public:
    ThreadSafeObserver(std::shared_ptr<Data> data)
        : data_(data)
        , mutex_(std::make_shared<std::mutex>()) {}
    
    void process() {
        std::lock_guard<std::mutex> lock(*mutex_);
        // 安全地訪問(wèn)data_
        // data_和mutex_的生命周期綁定在一起
    }
    
    // 創(chuàng)建觀察者副本
    ThreadSafeObserver clone() const {
        return ThreadSafeObserver(data_);  // 共享相同的mutex和數(shù)據(jù)
    }
};

綜合案例:一個(gè)線程安全、高性能的對(duì)象池

// 完整的最佳實(shí)踐示例
template<typename T>
class ThreadSafeObjectPool {
private:
    struct PooledObject {
        T object;
        bool in_use{false};
        std::chrono::steady_clock::time_point last_used;
    };
    
    // 使用unique_ptr管理池中對(duì)象
    std::vector<std::unique_ptr<PooledObject>> pool_;
    
    // 可用的對(duì)象使用weak_ptr引用
    std::vector<std::weak_ptr<T>> available_;
    
    // 線程安全
    mutable std::shared_mutex mutex_;
    
    // 避免循環(huán)引用的關(guān)鍵:自定義刪除器
    struct PoolDeleter {
        ThreadSafeObjectPool* pool;
        
        void operator()(T* ptr) {
            // 不是真的刪除,而是返回池中
            pool->return_to_pool(ptr);
        }
    };
    
public:
    // 獲取對(duì)象:返回帶自定義刪除器的shared_ptr
    std::shared_ptr<T> acquire() {
        std::unique_lock lock(mutex_);
        
        // 清理過(guò)期的weak_ptr
        available_.erase(
            std::remove_if(available_.begin(), available_.end(),
                [](const std::weak_ptr<T>& wp) { return wp.expired(); }),
            available_.end()
        );
        
        // 嘗試從可用對(duì)象中獲取
        for(auto it = available_.begin(); it != available_.end(); ++it) {
            if(auto sp = it->lock()) {
                // 找到可用對(duì)象
                available_.erase(it);
                
                // 查找對(duì)應(yīng)的PooledObject并標(biāo)記為使用中
                for(auto& pooled_obj : pool_) {
                    if(&pooled_obj->object == sp.get()) {
                        pooled_obj->in_use = true;
                        pooled_obj->last_used = std::chrono::steady_clock::now();
                        break;
                    }
                }
                
                return sp;
            }
        }
        
        // 創(chuàng)建新對(duì)象
        auto pooled_obj = std::make_unique<PooledObject>();
        T* raw_ptr = &pooled_obj->object;
        pooled_obj->in_use = true;
        pooled_obj->last_used = std::chrono::steady_clock::now();
        
        // 創(chuàng)建帶自定義刪除器的shared_ptr
        std::shared_ptr<T> sp(raw_ptr, PoolDeleter{this});
        
        // 存儲(chǔ)unique_ptr以管理生命周期
        pool_.push_back(std::move(pooled_obj));
        
        return sp;
    }
    
private:
    // 對(duì)象返回到池中(由自定義刪除器調(diào)用)
    void return_to_pool(T* ptr) {
        std::unique_lock lock(mutex_);
        
        // 查找對(duì)應(yīng)的PooledObject
        for(auto& pooled_obj : pool_) {
            if(&pooled_obj->object == ptr) {
                pooled_obj->in_use = false;
                
                // 創(chuàng)建新的weak_ptr添加到可用列表
                available_.push_back(
                    std::shared_ptr<T>(std::shared_ptr<T>{}, ptr)  // 別名構(gòu)造函數(shù)
                );
                break;
            }
        }
    }
    
    // 清理長(zhǎng)時(shí)間未用的對(duì)象
    void cleanup_old_objects(std::chrono::seconds max_idle_time) {
        std::unique_lock lock(mutex_);
        
        auto now = std::chrono::steady_clock::now();
        
        for(auto it = pool_.begin(); it != pool_.end(); ) {
            auto& pooled_obj = *it;
            
            if(!pooled_obj->in_use && 
               (now - pooled_obj->last_used) > max_idle_time) {
                // 從available_中移除對(duì)應(yīng)的weak_ptr
                available_.erase(
                    std::remove_if(available_.begin(), available_.end(),
                        [obj_ptr = &pooled_obj->object](const std::weak_ptr<T>& wp) {
                            if(auto sp = wp.lock()) {
                                return sp.get() == obj_ptr;
                            }
                            return false;
                        }),
                    available_.end()
                );
                
                // 刪除對(duì)象
                it = pool_.erase(it);
            } else {
                ++it;
            }
        }
    }
};

// 使用示例
void use_object_pool() {
    ThreadSafeObjectPool<DatabaseConnection> pool;
    
    // 多線程安全地獲取連接
    std::vector<std::thread> threads;
    for(int i = 0; i < 10; ++i) {
        threads.emplace_back([&pool, i]() {
            // 獲取連接(可能阻塞直到有可用連接)
            auto conn = pool.acquire();
            
            // 使用連接
            conn->execute_query("SELECT * FROM users");
            
            // conn離開(kāi)作用域,自動(dòng)返回到池中
            // 因?yàn)槭褂昧俗远x刪除器
        });
    }
    
    for(auto& t : threads) {
        t.join();
    }
}

智能指針的三大「生存法則」

法則一:所有權(quán)設(shè)計(jì)優(yōu)先

  • 能使用unique_ptr就不要用shared_ptr
  • 明確對(duì)象的所有權(quán)生命周期
  • 使用weak_ptr打破循環(huán)引用

法則二:性能意識(shí)常駐

  • 優(yōu)先使用make_shared/make_unique
  • 避免不必要的shared_ptr拷貝
  • 注意原子操作的開(kāi)銷(xiāo)

法則三:線程安全不假設(shè)

  • shared_ptr的線程安全僅限于控制塊
  • 指向的數(shù)據(jù)需要額外保護(hù)
  • 考慮使用不可變數(shù)據(jù)結(jié)構(gòu)

最終檢查清單

每次使用智能指針前問(wèn)自己:

1. 這個(gè)對(duì)象應(yīng)該被誰(shuí)擁有?

  • unique_ptr
  • shared_ptr

2. 是否有循環(huán)引用的可能?

  • 有(需weak_ptr) 
  • 無(wú)

3. 是否會(huì)在多線程中使用?

  • 是(需同步) 

4. 是否需要最優(yōu)性能?

  • 是(避免shared_ptr)

5. 是否傳遞所有權(quán)?

  • 是(移動(dòng)語(yǔ)義)
  • 否(傳遞引用)

從「會(huì)用」到「精通」

智能指針不是「銀彈」,而是「雙刃劍」。它解決了手動(dòng)管理內(nèi)存的煩惱,卻引入了更隱蔽的陷阱。真正的精通,不是記住語(yǔ)法,而是理解每個(gè)設(shè)計(jì)決策背后的權(quán)衡。

正如C++之父Bjarne Stroustrup所說(shuō):「C++的設(shè)計(jì)初衷是讓好的設(shè)計(jì)更容易,壞的設(shè)計(jì)更困難」。智能指針正是這一哲學(xué)的體現(xiàn)——它獎(jiǎng)勵(lì)清晰的所有權(quán)設(shè)計(jì),懲罰模糊的資源管理。

下次當(dāng)你寫(xiě)下std::shared_ptr時(shí),不妨停頓一秒,問(wèn)問(wèn)自己:「我真的需要共享所有權(quán)嗎?」這個(gè)簡(jiǎn)單的問(wèn)題,可能就是避免下一個(gè)深夜崩潰的關(guān)鍵。

到此這篇關(guān)于一文詳解C++中的智能指針避坑指南的文章就介紹到這了,更多相關(guān)C++智能指針內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 全面解析C++中的析構(gòu)函數(shù)

    全面解析C++中的析構(gòu)函數(shù)

    這篇文章主要介紹了C++中的析構(gòu)函數(shù),為C++入門(mén)學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2016-01-01
  • C++面向?qū)ο蠖嗉?jí)菜單向Arduino的移植問(wèn)題小結(jié)

    C++面向?qū)ο蠖嗉?jí)菜單向Arduino的移植問(wèn)題小結(jié)

    這篇文章主要介紹了C++面向?qū)ο蠖嗉?jí)菜單向Arduino的移植問(wèn)題及實(shí)現(xiàn)思路,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • C語(yǔ)言實(shí)現(xiàn)旅游資訊管理系統(tǒng)

    C語(yǔ)言實(shí)現(xiàn)旅游資訊管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)旅游資訊管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • QT5交叉編譯入門(mén)級(jí)教程(arm64、mips64)

    QT5交叉編譯入門(mén)級(jí)教程(arm64、mips64)

    交叉編譯就是在當(dāng)前系統(tǒng)平臺(tái)上,開(kāi)發(fā)編譯運(yùn)行于其它平臺(tái)的程序,比如本文硬件環(huán)境是x86平臺(tái),但是編譯出來(lái)的程序是在arm64架構(gòu)、mips64等架構(gòu)上運(yùn)行,本文給大家分享QT5交叉編譯入門(mén)級(jí)教程(arm64、mips64),感興趣的朋友一起看看吧
    2023-11-11
  • Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)分頁(yè)

    Qt數(shù)據(jù)庫(kù)應(yīng)用之實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)分頁(yè)

    數(shù)據(jù)庫(kù)分頁(yè)展示,在所有的涉及到數(shù)據(jù)庫(kù)記錄的項(xiàng)目中都是需要的。本文將利用Qt實(shí)現(xiàn)通用數(shù)據(jù)庫(kù)的分頁(yè)展示,感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下
    2022-02-02
  • C++調(diào)用迅雷接口解析XML下載功能(迅雷下載功能)

    C++調(diào)用迅雷接口解析XML下載功能(迅雷下載功能)

    這篇文章主要介紹了C++調(diào)用迅雷接口,封裝解析XML下載的類(lèi),功能簡(jiǎn)單,大家參考使用吧
    2013-11-11
  • 一文詳解C++17中的結(jié)構(gòu)化綁定

    一文詳解C++17中的結(jié)構(gòu)化綁定

    C++17中的結(jié)構(gòu)化綁定(structured binding)是指將指定名稱(chēng)綁定到初始化程序的子對(duì)象或元素,本文主要來(lái)和大家聊聊C++17中結(jié)構(gòu)化綁定的實(shí)現(xiàn),感興趣的小伙伴可以了解下
    2023-12-12
  • C語(yǔ)言memset函數(shù)詳解

    C語(yǔ)言memset函數(shù)詳解

    這篇文章主要介紹了C語(yǔ)言中的memset()函數(shù),包括其與memcpy()函數(shù)的區(qū)別,需要的朋友可以參考下,希望能夠給你帶來(lái)幫助
    2021-09-09
  • C++之memcpy導(dǎo)致的深拷貝問(wèn)題分析

    C++之memcpy導(dǎo)致的深拷貝問(wèn)題分析

    使用memcpy拷貝vector中自定義類(lèi)型元素(如string)時(shí),僅復(fù)制指針值導(dǎo)致懸空指針,引發(fā)未定義行為,而循環(huán)賦值通過(guò)調(diào)用賦值運(yùn)算符實(shí)現(xiàn)深拷貝,正確復(fù)制對(duì)象內(nèi)容,標(biāo)準(zhǔn)庫(kù)vector通過(guò)類(lèi)型特質(zhì)區(qū)分類(lèi)型,對(duì)非平凡類(lèi)型調(diào)用構(gòu)造/析值函數(shù),避免此類(lèi)問(wèn)題
    2025-09-09
  • 如何理解C++指針常量和常量指針

    如何理解C++指針常量和常量指針

    這篇文章主要介紹了如何理解C++指針常量和常量指針,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06

最新評(píng)論

澜沧| 尼木县| 个旧市| 平江县| 晋宁县| 墨竹工卡县| 抚松县| 土默特右旗| 武胜县| 浠水县| 天台县| 尼勒克县| 汾阳市| 德化县| 台北市| 恩平市| 清原| 胶州市| 明星| 原阳县| 察雅县| 高邮市| 乌拉特前旗| 古田县| 得荣县| 海城市| 枣强县| 临汾市| 崇左市| 自贡市| 同心县| 泸州市| 江阴市| 杭锦后旗| 库伦旗| 改则县| 象州县| 湾仔区| 崇左市| 石城县| 郑州市|