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

C++ vector使用以及底層核心剖析

 更新時間:2026年01月07日 10:18:00   作者:霧島聽藍  
本文全面拆解了C++標準庫中的vector容器,從基礎使用、核心接口、迭代器失效到底層實現(xiàn),詳細介紹了vector的各個方面,感興趣的朋友跟隨小編一起看看吧

        在 C++ 標準庫中,vector 是最常用的容器之一,它本質上是一個動態(tài)順序表,兼具數(shù)組的隨機訪問特性和動態(tài)擴容的靈活性。本文將從基礎使用、核心接口、迭代器失效、底層實現(xiàn)等維度,全面拆解 vector 的核心知識點,幫你徹底吃透這個容器。

一、vector 基礎使用

1. 頭文件與初始化

使用 vector 首先需要包含頭文件<vector>,它的初始化方式靈活多樣,適配不同場景:

#include <iostream>
#include <vector>
using namespace std;
void test_vector_init() {
    // 1. 空vector
    vector<int> v1;  
    // 2. 初始化10個元素,每個元素值為1
    vector<int> v2(10, 1);  
    // 3. 用v2的迭代器區(qū)間初始化v3(拷貝v2所有元素)
    vector<int> v3(v2.begin(), v2.end());  
    // 4. 列表初始化(C++11及以上)
    vector<int> v4{1, 2, 0};  
}

2. 三種遍歷方式

        vector 的遍歷和 string 高度相似,支持下標、迭代器、范圍 for 三種方式:

void test_vector_traverse() {
    vector<int> v{1, 2, 3, 4, 5};
    // 方式1:下標遍歷(隨機訪問特性)
    for (size_t i = 0; i < v.size(); i++) {
        cout << v[i] << " ";
    }
    cout << endl;
    // 方式2:迭代器遍歷
    vector<int>::iterator it = v.begin();
    while (it != v.end()) {
        cout << *it << " ";
        ++it;
    }
    cout << endl;
    // 方式3:范圍for(C++11及以上)
    for (auto e : v) {
        cout << e << " ";
    }
    cout << endl;
}

3. 插入與刪除

        vector 的插入(insert)和刪除(erase)是高頻操作,需注意迭代器的使用規(guī)則:

void test_vector_insert_erase() {
    vector<int> v(10, 1);  
    // 尾插元素2
    v.push_back(2);
    // 頭插元素3(insert僅支持迭代器傳參)
    v.insert(v.begin(), 3);
    // 在第5個位置前插入4(迭代器偏移)
    v.insert(v.begin() + 5, 4);
    for (auto e : v) {
        cout << e << " ";	// 輸出:3 1 1 1 1 4 1 1 1 1 1 1 2
    }
    cout << endl;
    // 尾刪元素
    v.pop_back();
    // 刪除第5個位置的元素
    v.erase(v.begin() + 5);
    for (auto e : v) {
        cout << e << " ";	// 輸出:3 1 1 1 1 1 1 1 1 1 1
    }
    cout << endl;
}

4. 二維 vector(二維數(shù)組)

        vector 支持嵌套定義實現(xiàn)二維數(shù)組,相比原生二維數(shù)組更靈活(每行長度可不同):

void test_vector_2d() {
    // 初始化10行5列的二維數(shù)組,每個元素初始值為1
    vector<int> v(5, 1);
    vector<vector<int>> vv(10, v);
    // 修改第3行第2列的元素(下標從0開始)
    vv[2][1] = 2;  
    // 遍歷二維vector
    for (size_t i = 0; i < vv.size(); i++) {
        for (size_t j = 0; j < vv[i].size(); j++) {
            cout << vv[i][j] << " ";
        }
        cout << endl;
    }
}

5. 實用案例:楊輝三角

        結合 vector 的初始化、resize、元素訪問等特性,實現(xiàn) LeetCode 經典題 “楊輝三角”:

class Solution {
public:
    vector<vector<int>> generate(int numRows) {
        // 初始化numRows行的二維vector
        vector<vector<int>> vv(numRows);
        for(size_t i = 0; i < numRows; i++) {
            // 第i行開辟i+1個空間,初始值為0
            vv[i].resize(i+1, 0);  
            // 每行首尾元素設為1
            vv[i].front() = vv[i].back() = 1;  
        }
        // 填充中間元素
        for(int i = 1; i < vv.size(); i++) {
            for(int j = 1; j < vv[i].size()-1; j++) {
                vv[i][j] = vv[i-1][j-1] + vv[i-1][j];
            }
        }
        return vv;
    }
};

二、vector 核心接口對比與細節(jié)

1. reserve:僅擴容,不初始化

vector 的reserve和 string 的reserve存在關鍵區(qū)別:

  • n < size()時,vector 的 reserve無任何操作;
  • string 的 reserve 若縮容(多數(shù)編譯器忽略),至少保證容量不低于 size ()。

2. resize:改變元素個數(shù),按需初始化

resize會直接修改 vector 的元素個數(shù),行為分三種情況:

  • n < size():刪除末尾元素,僅調整有效元素個數(shù);
  • size() < n < capacity():在末尾插入元素,用默認值初始化;
  • n > capacity():先擴容,再插入元素初始化。

注意:vector 默認按元素類型的默認值初始化(如 int 為 0),而 string 固定初始化為'\0'。

// resize接口原型(可指定初始化值)
void resize (size_type n, value_type val = value_type());

3. 不支持重載 <<和>>

vector 沒有默認的輸入輸出重載,需手動實現(xiàn)輸入輸出邏輯:

// 單個元素輸入
vector<int> v;
int x;
cin >> x;
v.push_back(x);
// 多個元素輸入(初始化5個元素)
vector<int> v1(5, 0);
for (size_t i = 0; i < 5; i++) {
    cin >> v1[i];
}

三、迭代器失效

迭代器失效是 vector 使用中最容易出錯的地方,本質是迭代器指向的空間失效指向位置的語義改變,主要分為兩類場景:

1. 擴容導致的迭代器失效(野指針)

當 vector 插入元素觸發(fā)擴容時,原空間會被釋放,之前的迭代器變?yōu)橐爸羔槪?/p>

// 錯誤示例:擴容后迭代器失效
void test_vector_invalid1() {
    vector<int> v{1,2,3,4};
    // 插入位置迭代器
    auto pos = v.begin() + 1;
    // 插入元素觸發(fā)擴容,原pos指向的空間被釋放
    v.insert(pos, 5);
    // 訪問失效迭代器,結果未定義
    cout << *pos << endl; 
}

解決方法:插入時記錄迭代器相對位置,擴容后重新修正迭代器:

iterator insert(iterator pos, const T& x) {
    assert(pos >= _start && pos <= _finish);
    if (_finish == _end_of_storage) {
        // 記錄相對位置
        size_t len = pos - _start;
        // 擴容
        reserve(capacity() == 0 ? 4 : 2 * capacity());
        // 修正迭代器指向新空間
        pos = _start + len;
    }
    // 元素后移 + 插入新元素
    iterator end = _finish - 1;
    while (end >= pos) {
        *(end + 1) = *end;
        --end;
    }
    *pos = x;
    ++_finish;
    // 返回新插入元素的迭代器
    return pos;
}

2. 插入 / 刪除導致的迭代器語義失效

(1)insert 后迭代器語義失效

insert 會挪動元素,原迭代器指向的位置語義改變(不再是原來的元素):

void test_vector_invalid2() {
    vector<int> v{1,5,2,3,4};
    auto p = find(v.begin(), v.end(), 2);
    if (p != v.end()) {
        // 插入后p不再指向2,而是指向新插入的40
        v.insert(p, 40);
        // 錯誤:修改的是40,而非原來的2
        (*p) *= 10; 
    }
}

解決方法:接收 insert 返回的新迭代器,重新定位:

auto p = find(v.begin(), v.end(), 2);
if (p != v.end()) {
    // 接收新迭代器,指向插入的40
    p = v.insert(p, 40);
    // 修改原來的2(p+1位置)
    (*(p + 1)) *= 10; 
}

(2)erase 后迭代器語義失效

erase 刪除元素后,原迭代器指向的位置變?yōu)橄乱粋€元素,若直接 ++ 會跳過元素或死循環(huán):

// 錯誤示例:刪除所有偶數(shù),迭代器失效導致漏刪/死循環(huán)
void test_vector_invalid3() {
    vector<int> v{1,2,3,4};
    auto it = v.begin();
    while (it != v.end()) {
        if (*it % 2 == 0) {
            v.erase(it); // 刪除后it失效
        }
        ++it; // 失效迭代器++,行為未定義
    }
}

解決方法:接收 erase 返回的迭代器(指向刪除元素的下一個位置):

// 正確版本:刪除所有偶數(shù)
void test_vector_erase_fix() {
    vector<int> v{1,2,3,4};
    auto it = v.begin();
    while (it != v.end()) {
        if (*it % 2 == 0) {
            // 接收返回值,更新迭代器
            it = v.erase(it);
        } else {
            ++it; // 僅非刪除場景++
        }
    }
    // 輸出:1 3
    for (auto e : v) cout << e << " ";
}

四、vector 底層實現(xiàn)關鍵細節(jié)

1. 迭代器區(qū)間構造(模板復用)

vector 的迭代器區(qū)間構造函數(shù)設計為模板函數(shù),支持任意容器的迭代器初始化(只要類型匹配):

// 類模板的成員函數(shù)可嵌套函數(shù)模板
template <class InputIterator>
vector(InputIterator first, InputIterator last) {
    while (first != last) {
        push_back(*first);
        ++first;
    }
}
// 用法:僅拷貝v1的前3個元素
vector<int> v1{1,2,3,4,5};
vector<int> v2(v1.begin(), v1.begin()+3);

2. 淺拷貝問題修復

vector 擴容時若用 memcpy 拷貝元素,會導致自定義類型(如 string)的淺拷貝問題,需改用賦值運算符:

void reserve(size_t n) {
    if (n > capacity()) {
        size_t old_size = size();
        T* tmp = new T[n];
        // 錯誤:memcpy是淺拷貝,自定義類型會析構重復釋放
        // memcpy(tmp, _start, size() * sizeof(T));
        // 正確:調用T的賦值運算符,深拷貝自定義類型
        for (size_t i = 0; i < old_size; i++) {
            tmp[i] = _start[i];
        }
        delete[] _start;
        _start = tmp;
        _finish = _start + old_size;
        _end_of_storage = _start + n;
    }
}

3. 內置類型的 “偽構造函數(shù)”

        vector 的 resize 接口默認參數(shù)為T(),為了適配內置類型(如 int),C++ 編譯器會為內置類型模擬構造函數(shù):

void resize(size_t n, T val = T()) {
    if (n < size()) {
        _finish = _start + n;
    } else {
        reserve(n);
        while (_finish < _start + n) {
            *_finish = val;
            ++_finish;
        }
    }
}
// 調用示例:int()等價于0,double()等價于0.0
v.resize(10); // 內置類型用默認值初始化

4. const_iterator 的 typename 修飾

        在模板中使用vector<T>::const_iterator時,需加typename說明這是類型(否則編譯器視為靜態(tài)成員):

// 錯誤:編譯器無法區(qū)分const_iterator是類型還是成員
// vector<T>::const_iterator it = v.begin();
// 正確1:加typename說明是類型
typename vector<T>::const_iterator it1 = v.begin();
// 正確2:用auto自動推導(推薦)
auto it2 = v.begin();

到此這篇關于C++ vector:從使用到底層核心剖析的文章就介紹到這了,更多相關C++ vector用法內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論

得荣县| 鄂托克旗| 比如县| 皋兰县| 永登县| 台湾省| 连江县| 垦利县| 商丘市| 丁青县| 潼南县| 两当县| 莱西市| 连江县| 苏尼特右旗| 双江| 阳谷县| 桃园市| 海宁市| 平遥县| 历史| 堆龙德庆县| 新绛县| 新晃| 水富县| 和硕县| 沁源县| 麻江县| 垦利县| 沂南县| 于都县| 望江县| 桦南县| 巧家县| 盘锦市| 大英县| 灵石县| 怀化市| 乐陵市| 清镇市| 通辽市|