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

C++中std::vector Vs std::deque VS std::list的對比分析

 更新時間:2025年09月18日 10:30:09   作者:點云SLAM  
本文對比了C++中vector、deque和list的核心差異,重點分析內(nèi)存布局、性能特性及迭代器失效規(guī)則,建議優(yōu)先使用vector(緩存友好、高效遍歷),deque適用于雙端操作,list僅在需穩(wěn)定迭代器或O(1)節(jié)點移動時使用,強調(diào)避免頻繁小分配與迭代器失效風(fēng)險

1) 核心差異速覽

  • std::vector:連續(xù)內(nèi)存、隨機訪問 O(1)、尾部 push_back 攤還 O(1)、中間插入/刪除 O(n),非常緩存友好。
  • std::deque:分段(block)存儲,不是整體連續(xù);隨機訪問 O(1)(但常數(shù)比 vector 大);兩端插入/刪除攤還 O(1);中間插入/刪除 O(n)。適合雙端隊列。
  • std::list:雙向鏈表,節(jié)點分散、隨機訪問 O(n)、在已知位置插入/刪除 O(1)、splice(跨 list 移動)O(1) 并且不使其他迭代器失效(被移動元素的迭代器繼續(xù)有效但指向新容器)。適合需要穩(wěn)定指針/節(jié)點移動而不復(fù)制元素的場景。

2) 內(nèi)存布局與緩存局部性(關(guān)鍵影響性能)

  • std::vector:元素緊密連續(xù)排列(C-style 數(shù)組),單次分配大塊內(nèi)存 → 最佳緩存局部性 / CPU 預(yù)取效果好,遍歷與數(shù)值運算非??臁_m合數(shù)值、圖像、點云等大量數(shù)據(jù)的順序處理。
  • std::deque:實現(xiàn)為若干固定大小塊(segments)+ 一個“map”(指針數(shù)組)指向塊。元素在邏輯上是連續(xù)的,但物理上分段存放;隨機訪問需要兩級尋址(map + block index),因此本地性和常數(shù)開銷不如 vector。
  • std::list:每個元素封裝在節(jié)點里(元素 + 前向/后向指針),每個節(jié)點通常是獨立分配 → 極差的緩存局部性 & 大量小分配開銷。只有在需要節(jié)點穩(wěn)定性和 O(1) 插入/刪除時才有價值。

3) 算法復(fù)雜度(常見操作 Big-O)

(常見且直觀版本)

操作vectordequelist
隨機訪問 operator[]O(1)(連續(xù))O(1)(分段)O(n)
push_back攤還 O(1)(可能重分配)攤還 O(1)O(1)
push_frontO(n)(要移動元素)攤還 O(1)O(1)
插入/刪除 中間位置O(n)(移動元素)O(n)(移動/拷貝)O(1)(若已知迭代器)
splice / 跨容器移動O(1)(不復(fù)制元素)
遍歷(線性訪問成本)最快(緩存)中等最慢(指針跳轉(zhuǎn))

注:

vector 的尾部 push_back攤還 O(1)(因為擴容策略),但發(fā)生重分配時會拷貝/移動全部元素。

deque 在兩端插入通常是 O(1),但插入可能導(dǎo)致 map 調(diào)整。list 的插入/刪除在已定位節(jié)點時是真正 O(1)。(表中結(jié)論與 cppreference 的復(fù)雜度說明一致)

4) 迭代器 / 指針 / 引用失效規(guī)則(非常重要)

這是容易出 bug 的地方,下面列出常見操作如何影響已有的迭代器/指針/引用(以當(dāng)前標(biāo)準(zhǔn)行為為準(zhǔn))。

std::vector

  • 重分配(capacity 變化):會使所有迭代器、指針和引用失效(因為底層緩沖區(qū)搬移)。
  • push_back / emplace_back:若觸發(fā)重分配 → 所有失效;若不觸發(fā)重分配 → 僅影響 end()(過去的 end 不再有效)。
  • insert(非尾部):若不重分配 → 使插入點之后的迭代器/引用失效(元素被移動);若重分配 → 全部失效。
  • erase:擦除后從被擦除位置到末尾的迭代器/引用失效。

std::deque

規(guī)則稍復(fù)雜,總結(jié)常見點:

  • 在中間 insert/erase:通常使所有迭代器失效(實現(xiàn)細(xì)節(jié)有所不同,但應(yīng)當(dāng)假設(shè)會全失效)。
  • 在兩端(push_front/push_back / pop_front/pop_back:通常是 O(1),但有可能使迭代器失效(特別是當(dāng)內(nèi)部 map/blocks 需要擴展時)。擦除兩端通常只使被擦除元素的迭代器失效,但 end() 在某些情況也會失效。簡而言之:不要對 deque 假設(shè)嚴(yán)格的迭代器穩(wěn)定性。

std::list

  • 插入/移動(insert, splice 等):不會使其他迭代器/引用失效(節(jié)點只是調(diào)整指針)。
  • 擦除:只有指向被擦除元素的迭代器/引用失效;其他迭代器保持有效。
  • splice:把一段節(jié)點從一個 list 移到另一個 list,不復(fù)制元素、也不失效迭代器(但指向被移動元素的迭代器現(xiàn)在屬于新容器)。這點非常有用(實現(xiàn) LRU、鏈表合并等)。

5) 典型使用場景與實戰(zhàn)建議(什么時候選哪個)

優(yōu)先選擇 std::vector

  • 默認(rèn)容器:絕大多數(shù)場景(順序訪問、數(shù)值計算、排序、與 C API 交互、內(nèi)存緊湊很重要)都用 vector
  • 優(yōu)化項:對頻繁 push_back 的場景先 reserve(),用 emplace_back() 來避免多余拷貝/移動。reserve 可避免重分配從而保持指針/引用穩(wěn)定。

選擇 std::deque

  • 需要在兩端高效插入/刪除(如雙端隊列、實現(xiàn) std::stack 默認(rèn)底層)。
  • 不需要與 C 風(fēng)格連續(xù)內(nèi)存交互,且能接受略差的緩存局部性。不要以為 deque 保證插入不失效 — 對迭代器失效要有防范。

選擇 std::list

  • 必須在容器內(nèi)部頻繁在已知迭代器處做 O(1) 插入/刪除,且必須要迭代器/引用穩(wěn)定(例如實現(xiàn)復(fù)雜鏈?zhǔn)浇Y(jié)構(gòu)、需要頻繁 splice 的場景)。
  • 否則通常不推薦:鏈表遍歷慢、內(nèi)存開銷大(節(jié)點 + 分配器元數(shù)據(jù)),并且常常有更好的替代(vector + index、deque、或 intrusive containers)。

6) 常見陷阱 & 優(yōu)化技巧(實戰(zhàn)干貨)

  • 默認(rèn)用 vector:現(xiàn)代 C++ 社區(qū)共識是“首選 vector,除非有明確理由”。
  • 避免頻繁小分配std::list 每個節(jié)點通常單獨分配,帶來 malloc/allocator 開銷;如果必須,考慮自定義內(nèi)存池或 boost::intrusive_list。
  • reserve() 避免重分配:對于 vector,若能預(yù)知元素數(shù)量,v.reserve(n) 會大幅降低重分配/拷貝成本并保持指針穩(wěn)定。

刪除元素時的正確寫法(在遍歷中安全刪元素):

vector / deque

for (auto it = c.begin(); it != c.end(); ) {
    if (should_erase(*it)) it = c.erase(it); // erase 返回下一個迭代器(C++11 起)
    else ++it;
}

list

for (auto it = l.begin(); it != l.end(); ) {
    if (cond) it = l.erase(it); // O(1),其他迭代器不受影響
    else ++it;
}

erase-remove 慣用法:對 vector 批量刪除滿足條件的元素應(yīng)該使用:

v.erase(std::remove_if(v.begin(), v.end(), pred), v.end());

這比在循環(huán)中逐個 erase 快很多。

  • 避免在 deque 中假設(shè)迭代器穩(wěn)定性:如果需要穩(wěn)定引用并且要頻繁在兩端操作,重新驗證你的需求;有時 vector + index 更簡單且更快。
  • splice 是鏈表的王牌:當(dāng)需要移動大量元素而不做復(fù)制/構(gòu)造/析構(gòu)時,用 list::splice (O(1))能大幅提高性能。

7) 代碼示例 — 常見用法與陷阱演示

預(yù)分配避免重分配(vector)

std::vector<MyType> v;
v.reserve(1000);           // 預(yù)分配,避免擴容導(dǎo)致的整體移動
for (...) v.emplace_back(...); // in-place 構(gòu)造,避免拷貝

遍歷時刪除(安全寫法)

// vector / deque
for (auto it = v.begin(); it != v.end(); ) {
    if (need_erase(*it)) it = v.erase(it);
    else ++it;
}

// list
for (auto it = l.begin(); it != l.end(); ) {
    if (need_erase(*it)) it = l.erase(it); // 只使被刪節(jié)點的迭代器失效
    else ++it;
}

list::splice(O(1) 移動節(jié)點,不復(fù)制)

std::list<int> a{1,2,3,4}, b{10,11};
// 把 a 中的 [2,4) 移到 b 的開頭
auto first = std::next(a.begin()); // 指向 2
auto last  = std::next(first, 2);  // 指向 4 (不含)
b.splice(b.begin(), a, first, last); // O(1)

8) 快速參考表(便于記憶)

  • 需要最快的遍歷/數(shù)值處理/與 C 互操作std::vector
  • 需要兩端高效插入/彈出(deque/queue/stack)std::deque
  • 需要在已知位置 O(1) 插入/刪除 & 穩(wěn)定迭代器/指針/引用;或需要 O(1) 跨容器移動節(jié)點std::list(并考慮內(nèi)存/緩存開銷)

9)std::queue應(yīng)用示例

下面是一個 C++11/17 標(biāo)準(zhǔn)庫實現(xiàn)的多線程生產(chǎn)者-消費者模型完整示例

采用 std::thread、std::mutexstd::condition_variable,隊列用 std::queue 封裝,支持多生產(chǎn)者、多消費者。

示例代碼

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <chrono>

// 線程安全隊列
template <typename T>
class ThreadSafeQueue {
public:
    void push(T value) {
        {
            std::lock_guard<std::mutex> lock(mtx_);
            queue_.push(std::move(value));
        }
        cv_.notify_one(); // 喚醒一個等待的消費者
    }

    T pop() {
        std::unique_lock<std::mutex> lock(mtx_);
        cv_.wait(lock, [this]{ return !queue_.empty() || done_; });
        if (queue_.empty()) {
            return T(); // 若結(jié)束且隊列空,返回默認(rèn)值
        }
        T value = std::move(queue_.front());
        queue_.pop();
        return value;
    }

    void shutdown() {
        {
            std::lock_guard<std::mutex> lock(mtx_);
            done_ = true;
        }
        cv_.notify_all(); // 喚醒所有等待線程
    }

private:
    std::queue<T> queue_;
    std::mutex mtx_;
    std::condition_variable cv_;
    bool done_ = false;
};

// ------------------- 生產(chǎn)者/消費者測試 -------------------
void producer(ThreadSafeQueue<int>& q, int id, int count) {
    for (int i = 0; i < count; i++) {
        std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模擬耗時
        int value = id * 100 + i;
        q.push(value);
        std::cout << "[Producer " << id << "] produced: " << value << "\n";
    }
}

void consumer(ThreadSafeQueue<int>& q, int id) {
    while (true) {
        int value = q.pop();
        if (value == 0 && q.pop() == 0) break; // 簡單退出條件(可換為特殊結(jié)束標(biāo)記)
        if (value != 0) {
            std::cout << "    [Consumer " << id << "] consumed: " << value << "\n";
        }
    }
}

int main() {
    ThreadSafeQueue<int> q;

    // 啟動多個生產(chǎn)者和消費者
    std::thread p1(producer, std::ref(q), 1, 5);
    std::thread p2(producer, std::ref(q), 2, 5);

    std::thread c1(consumer, std::ref(q), 1);
    std::thread c2(consumer, std::ref(q), 2);

    // 等生產(chǎn)者結(jié)束
    p1.join();
    p2.join();

    // 通知消費者結(jié)束
    q.shutdown();

    c1.join();
    c2.join();

    std::cout << "All threads finished.\n";
    return 0;
}

運行邏輯

  1. 生產(chǎn)者線程 持續(xù)往隊列里放任務(wù) (push)。
  2. 消費者線程 調(diào)用 pop,若隊列為空則阻塞等待。
  3. shutdown() 用于通知消費者退出。
  4. std::condition_variable 保證高效等待,而不是忙輪詢。

輸出示例(順序可能不同,因為多線程)

[Producer 1] produced: 100
[Producer 2] produced: 200
    [Consumer 1] consumed: 100
    [Consumer 2] consumed: 200
[Producer 1] produced: 101
[Producer 2] produced: 201
    [Consumer 1] consumed: 101
    [Consumer 2] consumed: 201
...
All threads finished.

10)總結(jié)

  • 首選 std::vector(最快、最省內(nèi)存、最常用);
  • 如果必須在兩端頻繁操作,考慮 std::deque(犧牲一些局部性和常數(shù));
  • 只有在確實需要節(jié)點級別穩(wěn)定性或 O(1) splice/插入/刪除時才用 std::list(并準(zhǔn)備承擔(dān)內(nèi)存與緩存的代價)。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • C++中const修飾符的詳解及其作用介紹

    C++中const修飾符的詳解及其作用介紹

    這篇文章主要介紹了C++中const修飾符的詳解及其作用介紹,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-09-09
  • C++中的數(shù)字轉(zhuǎn)字符串to_string

    C++中的數(shù)字轉(zhuǎn)字符串to_string

    這篇文章主要介紹了C++中的數(shù)字轉(zhuǎn)字符串to_string,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C語言怎么連接兩個數(shù)組的內(nèi)容你知道嗎

    C語言怎么連接兩個數(shù)組的內(nèi)容你知道嗎

    這篇文章主要為大家介紹了C語言怎么連接兩個數(shù)組的內(nèi)容,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-01-01
  • Qt中QByteArray?類型的使用詳解

    Qt中QByteArray?類型的使用詳解

    QByteArray是Qt中處理原始字節(jié)數(shù)據(jù)和8位字符串的核心容器類,本文就來詳解的介紹一下QByteArray?類型的使用,感興趣的可以了解一下
    2025-12-12
  • VS2019創(chuàng)建c++動態(tài)鏈接庫dll與調(diào)用方法實踐

    VS2019創(chuàng)建c++動態(tài)鏈接庫dll與調(diào)用方法實踐

    動態(tài)鏈接庫是一個包含可由多個程序同時使用的代碼和數(shù)據(jù)的庫,本文主要介紹了VS2019創(chuàng)建c++動態(tài)鏈接庫dll與調(diào)用方法,具有一定的參考價值,感興趣的可以了解一下
    2024-06-06
  • 使用C語言繪制柱形圖的示例代碼

    使用C語言繪制柱形圖的示例代碼

    常用的統(tǒng)計圖有條形圖、柱形圖、折線圖、曲線圖、餅圖、環(huán)形圖、扇形圖,這篇文章主要為大家介紹了C語言中繪制條形圖和柱形圖的方法,需要的可以參考下
    2024-02-02
  • C語言版醫(yī)院管理系統(tǒng)

    C語言版醫(yī)院管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了C語言版醫(yī)院管理系統(tǒng),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-01-01
  • 簡單談?wù)凜++中指針與引用的區(qū)別

    簡單談?wù)凜++中指針與引用的區(qū)別

    指針和引用在C++中很常用,但是對于它們之間的區(qū)別很多初學(xué)者都不是太熟悉,下面來談?wù)勊麄?者之間的區(qū)別和用法
    2017-04-04
  • 最新評論

    紫阳县| 左贡县| 玉屏| 二连浩特市| 沂水县| 缙云县| 东丽区| 金堂县| 临泽县| 静安区| 禄丰县| 诸城市| 龙岩市| 杭锦旗| 阿合奇县| 沈阳市| 定边县| 阜南县| 白河县| 烟台市| 泸水县| 彰化县| 朔州市| 桦川县| 孙吴县| 泉州市| 洛阳市| 苍南县| 宜昌市| 沽源县| 睢宁县| 阳城县| 左贡县| 雷州市| 汾阳市| 凯里市| 儋州市| 建阳市| 习水县| 曲周县| 河北省|