欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++之初始化列表詳解(initializer_list)

 更新時(shí)間:2025年09月18日 14:20:42   作者:MzKyle  
C++11引入std::initializer_list,用于封裝列表初始化的語法糖,實(shí)現(xiàn)容器、函數(shù)等場景的統(tǒng)一初始化方式,其本質(zhì)是輕量級只讀視圖,不存儲(chǔ)元素,僅通過指針和長度管理序列,支持容器構(gòu)造、參數(shù)傳遞等操作,但需注意生命周期與只讀限制

在 C++ 編程中,我們經(jīng)常會(huì)用到形如 vector<int> v = {1, 2, 3, 4}; 的語法——用花括號包裹一組元素直接初始化容器。

這種直觀且簡潔的寫法背后,依賴于 C++11 引入的一個(gè)特殊類型:std::initializer_list

它不僅是列表初始化的“橋梁”,更是 C++ 標(biāo)準(zhǔn)庫設(shè)計(jì)中連接語法糖與底層實(shí)現(xiàn)的關(guān)鍵機(jī)制。

一、initializer_list的本質(zhì)

std::initializer_list<T> 是 C++11 新增的標(biāo)準(zhǔn)庫類型,定義于 <initializer_list> 頭文件中。

它的核心作用是:封裝一組同類型元素的初始化列表,為編譯器提供一種統(tǒng)一的方式處理花括號 {} 包裹的元素序列。

簡單來說,當(dāng)你寫下 {a, b, c, d} 這樣的代碼時(shí),編譯器會(huì)自動(dòng)將這組元素轉(zhuǎn)換為一個(gè) initializer_list<T> 類型的臨時(shí)對象(其中 T 是元素的類型)。

這個(gè)臨時(shí)對象可以被傳遞給函數(shù)、作為構(gòu)造函數(shù)參數(shù),或用于賦值操作,從而實(shí)現(xiàn)“用一組值直接初始化對象”的目的。

二、initializer_list的底層結(jié)構(gòu):輕量級的“元素視圖”

initializer_list<T> 本身并不是一個(gè)容器(如 vectorarray),而是一個(gè)輕量級的“視圖”(view)——它不存儲(chǔ)元素本身,僅存儲(chǔ)指向元素序列的指針和序列長度。

其內(nèi)部結(jié)構(gòu)可簡化為:

template <class T>
class initializer_list {
public:
    using value_type = T;
    using reference = const T&;  // 注意:元素是只讀的
    using const_reference = const T&;
    using size_type = size_t;
    using iterator = const T*;   // 迭代器是 const 指針
    using const_iterator = const T*;

    // 構(gòu)造函數(shù)(由編譯器隱式調(diào)用,用戶無法直接構(gòu)造)
    constexpr initializer_list(const T* begin, const T* end) 
        : _M_array(begin), _M_size(end - begin) {}

    // 迭代器接口
    constexpr const T* begin() const noexcept { return _M_array; }
    constexpr const T* end() const noexcept { return _M_array + _M_size; }
    constexpr size_t size() const noexcept { return _M_size; }

private:
    const T* _M_array;  // 指向元素序列的首地址(編譯器分配)
    size_t _M_size;     // 元素個(gè)數(shù)
};

從結(jié)構(gòu)可見,initializer_list<T> 的核心特征是:

  1. 只讀性:元素指針 _M_arrayconst T*,迭代器也是 const T*,意味著無法通過 initializer_list 修改元素值(元素本身可能是可修改的,但列表視圖是只讀的)。
  2. 臨時(shí)性initializer_list 指向的元素序列由編譯器在棧上分配,生命周期與初始化列表的作用域一致(通常是臨時(shí)對象)。
  3. 輕量性:僅包含兩個(gè)成員(指針和長度),因此復(fù)制 initializer_list 時(shí)成本極低(僅復(fù)制指針和長度,不復(fù)制元素)。

三、initializer_list與vector<int>的“協(xié)作”

為什么 initializer_list<int> 能構(gòu)造 vector<int>?核心原因是 std::vector 專門設(shè)計(jì)了接受 initializer_list<T> 的構(gòu)造函數(shù),這是標(biāo)準(zhǔn)庫容器對列表初始化的“主動(dòng)適配”。

1. vector 的 initializer_list 構(gòu)造函數(shù)

std::vector<T> 的構(gòu)造函數(shù)中,有一個(gè)重載專門用于接收 initializer_list<T>

template <class T, class Allocator = std::allocator<T>>
class vector {
public:
    // 從 initializer_list 初始化
    vector(std::initializer_list<T> init, const Allocator& alloc = Allocator());
    // 其他構(gòu)造函數(shù)(如無參、指定大小、迭代器范圍等)
};

這個(gè)構(gòu)造函數(shù)的內(nèi)部實(shí)現(xiàn)邏輯大致是:

  1. 接收 initializer_list<T> 對象 init
  2. 調(diào)用 init.begin()init.end() 獲取元素序列的起始和結(jié)束地址;
  3. 分配足夠的內(nèi)存(大小為 init.size());
  4. 遍歷 initializer_list 中的元素,將它們逐個(gè)復(fù)制到 vector 的內(nèi)存中。

例如,當(dāng)我們寫 vector<int> v = {1, 2, 3, 4}; 時(shí),編譯器會(huì)執(zhí)行以下步驟:

  • {1, 2, 3, 4} 轉(zhuǎn)換為 initializer_list<int> 臨時(shí)對象(假設(shè)為 init),其中 init.begin() 指向 1 的地址,init.size() 為 4;
  • 調(diào)用 vector<int>vector(initializer_list<int>) 構(gòu)造函數(shù),傳入 init;
  • 構(gòu)造函數(shù)根據(jù) init 的元素序列,在 vector 內(nèi)部初始化 4 個(gè)元素,最終得到包含 1,2,3,4 的向量。

2. 為什么直接傳四個(gè) int 不行?

當(dāng)我們嘗試用 emplace_back(nums[i], nums[j], nums[left], nums[right]) 構(gòu)造 vector<int> 時(shí),實(shí)際是向 vector 的構(gòu)造函數(shù)傳遞了四個(gè)獨(dú)立的 int 參數(shù)。但 vector<int> 并沒有接受“4 個(gè) int”的構(gòu)造函數(shù)——它的構(gòu)造函數(shù)要么接受長度和初始值(如 vector(4, 0)),要么接受迭代器范圍,要么接受 initializer_list<int>。因此,直接傳遞四個(gè) int 會(huì)導(dǎo)致“無匹配的構(gòu)造函數(shù)”錯(cuò)誤。

initializer_list<int> 恰好匹配了 vector 為列表初始化設(shè)計(jì)的構(gòu)造函數(shù),因此能夠正確初始化。

四、initializer_list的使用場景:不止于容器初始化

initializer_list 的作用遠(yuǎn)不止初始化容器,它是 C++ 中“列表初始化”語法的通用機(jī)制,適用于多種場景:

1. 容器初始化與賦值

這是最常見的場景。所有標(biāo)準(zhǔn)庫容器(vector、listmap、set 等)都提供了接受 initializer_list 的構(gòu)造函數(shù)和賦值運(yùn)算符:

#include <map>
#include <set>

// 初始化 vector
std::vector<int> v = {1, 2, 3};

// 初始化 map(鍵值對列表)
std::map<std::string, int> m = {{"a", 1}, {"b", 2}};

// 賦值操作
v = {4, 5, 6};  // 調(diào)用 vector::operator=(initializer_list<int>)

2. 函數(shù)參數(shù):接收變長同類型參數(shù)

initializer_list 可以作為函數(shù)參數(shù),接收任意數(shù)量的同類型元素(類似“變長參數(shù)列表”,但限制為同類型)。例如,實(shí)現(xiàn)一個(gè)計(jì)算多個(gè)整數(shù)之和的函數(shù):

#include <initializer_list>
#include <iostream>

int sum(std::initializer_list<int> nums) {
    int total = 0;
    for (int num : nums) {  // 可通過范圍 for 遍歷
        total += num;
    }
    return total;
}

int main() {
    std::cout << sum({1, 2, 3, 4}) << std::endl;  // 輸出 10
    return 0;
}

這里的 sum({1,2,3,4}) 中,{1,2,3,4} 被轉(zhuǎn)換為 initializer_list<int>,作為參數(shù)傳入函數(shù),函數(shù)通過迭代器遍歷所有元素。

3. 自定義類型的列表初始化

我們可以為自定義類添加接受 initializer_list 的構(gòu)造函數(shù),使其支持列表初始化:

#include <initializer_list>
#include <vector>

class MyArray {
private:
    std::vector<int> data;
public:
    // 支持列表初始化
    MyArray(std::initializer_list<int> init) : data(init) {}

    void print() {
        for (int num : data) {
            std::cout << num << " ";
        }
    }
};

int main() {
    MyArray arr = {10, 20, 30};  // 調(diào)用 MyArray(initializer_list<int>)
    arr.print();  // 輸出 "10 20 30"
    return 0;
}

通過這種方式,自定義類型可以像標(biāo)準(zhǔn)容器一樣使用直觀的列表初始化語法。

4. 返回值:函數(shù)返回一組同類型元素

函數(shù)也可以返回 initializer_list<T>,方便返回一組臨時(shí)元素:

#include <initializer_list>

std::initializer_list<int> get_numbers() {
    return {1, 2, 3};  // 返回初始化列表
}

int main() {
    for (int num : get_numbers()) {
        std::cout << num << " ";  // 輸出 "1 2 3"
    }
    return 0;
}

注意:返回的 initializer_list 指向的元素是臨時(shí)的,因此不能存儲(chǔ)其副本并在后續(xù)使用(生命周期已結(jié)束)。

五、列表初始化的優(yōu)先級:為什么{}會(huì)優(yōu)先匹配initializer_list?

當(dāng)一個(gè)類同時(shí)有多個(gè)構(gòu)造函數(shù)時(shí),編譯器在處理 {} 初始化時(shí)會(huì)有明確的優(yōu)先級:如果存在接受 initializer_list 的構(gòu)造函數(shù),{} 初始化會(huì)優(yōu)先匹配該構(gòu)造函數(shù),而非其他重載。

例如:

#include <initializer_list>
#include <iostream>

class MyClass {
public:
    // 接受 initializer_list 的構(gòu)造函數(shù)
    MyClass(std::initializer_list<int> list) {
        std::cout << "Initializer_list constructor: " << list.size() << " elements\n";
    }

    // 接受兩個(gè) int 的構(gòu)造函數(shù)
    MyClass(int a, int b) {
        std::cout << "Two int constructor: " << a << ", " << b << "\n";
    }
};

int main() {
    MyClass obj1(1, 2);  // 調(diào)用 MyClass(int, int)
    MyClass obj2{1, 2};  // 優(yōu)先調(diào)用 MyClass(initializer_list<int>)
    return 0;
}

輸出結(jié)果:

Two int constructor: 1, 2
Initializer_list constructor: 2 elements

這一規(guī)則確保了 {} 語法與列表初始化的語義一致,避免了歧義。如果確實(shí)需要調(diào)用非 initializer_list 構(gòu)造函數(shù),可以使用圓括號 () 而非花括號 {}。

六、initializer_list的限制與注意事項(xiàng)

盡管 initializer_list 方便易用,但它的設(shè)計(jì)也有明確的限制,使用時(shí)需特別注意:

1. 元素必須是同類型

initializer_list<T> 要求所有元素的類型必須相同(或可隱式轉(zhuǎn)換為 T)。

例如,{1, 2.0, 3}2.0double,若 Tint,則 2.0 會(huì)被隱式轉(zhuǎn)換為 2;若無法轉(zhuǎn)換(如 {1, "hello"}),則編譯報(bào)錯(cuò)。

2. 元素是只讀的

initializer_list<T> 的迭代器是 const T*,因此無法通過 initializer_list 修改元素值:

#include <initializer_list>

void modify(std::initializer_list<int> list) {
    // 錯(cuò)誤:不能修改元素(迭代器是 const)
    // *list.begin() = 100;  // 編譯報(bào)錯(cuò):assignment of read-only location
}

如果需要修改元素,需先將 initializer_list 中的元素復(fù)制到可修改的容器(如 vector)中。

3. 生命周期與臨時(shí)對象

initializer_list 指向的元素序列由編譯器在棧上分配,是臨時(shí)對象,其生命周期與初始化列表的作用域一致。因此,不能存儲(chǔ) initializer_list 的副本并在其生命周期外使用

#include <initializer_list>
#include <vector>

// 錯(cuò)誤示例:返回的 initializer_list 指向已銷毀的元素
std::initializer_list<int> get_list() {
    return {1, 2, 3};  // 元素在函數(shù)返回后銷毀
}

int main() {
    auto list = get_list();
    // 未定義行為:list 指向的元素已被釋放
    // for (int num : list) { ... }
    return 0;
}

4. 不能直接構(gòu)造 initializer_list

initializer_list 沒有公有的構(gòu)造函數(shù),用戶無法手動(dòng)創(chuàng)建其實(shí)例,只能通過 {} 語法由編譯器自動(dòng)生成:

// 錯(cuò)誤:無法直接構(gòu)造 initializer_list
std::initializer_list<int> list(1, 2, 3);  // 編譯報(bào)錯(cuò)

七、initializer_list的設(shè)計(jì)意義

initializer_list 看似簡單,卻是 C++ 語言進(jìn)化中“語法糖”與“底層邏輯”結(jié)合的典范。它的核心價(jià)值在于:

  1. 統(tǒng)一初始化語法:讓數(shù)組、容器、自定義類型都能通過 {} 實(shí)現(xiàn)直觀的初始化,減少記憶負(fù)擔(dān)。
  2. 簡化容器使用:無需手動(dòng)調(diào)用 push_back 或指定大小,直接通過元素列表初始化容器。
  3. 支持變長同類型參數(shù):為函數(shù)提供了一種簡潔的方式接收任意數(shù)量的同類型元素,比 C 風(fēng)格的變長參數(shù)(va_list)更安全、更易用。

總結(jié)

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

相關(guān)文章

  • 嵌入式C語言查表法在項(xiàng)目中的應(yīng)用

    嵌入式C語言查表法在項(xiàng)目中的應(yīng)用

    今天小編就為大家分享一篇關(guān)于嵌入式C語言查表法在項(xiàng)目中的應(yīng)用,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Qt自定義實(shí)現(xiàn)一個(gè)等待提示Ui控件

    Qt自定義實(shí)現(xiàn)一個(gè)等待提示Ui控件

    等待樣式控件是我們在做UI時(shí)出場率還挺高的控件之一,所以這篇文章主要為大家介紹了Qt如何自定義一個(gè)好看的等待提示Ui控件,感興趣的可以了解下
    2024-01-01
  • C語言實(shí)現(xiàn)貪吃蛇游戲演示

    C語言實(shí)現(xiàn)貪吃蛇游戲演示

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)貪吃蛇游戲演示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10
  • C++ 復(fù)制控制之復(fù)制構(gòu)造函數(shù)的實(shí)現(xiàn)

    C++ 復(fù)制控制之復(fù)制構(gòu)造函數(shù)的實(shí)現(xiàn)

    所謂的“復(fù)制控制”即通過這三個(gè)成員函數(shù)控制對象復(fù)制的過程,本文主要介紹了C++ 復(fù)制控制之復(fù)制構(gòu)造函數(shù)的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-11-11
  • 利用OpenCV實(shí)現(xiàn)局部動(dòng)態(tài)閾值分割

    利用OpenCV實(shí)現(xiàn)局部動(dòng)態(tài)閾值分割

    這篇文章主要為大家詳細(xì)介紹了利用OpenCV實(shí)現(xiàn)局部動(dòng)態(tài)閾值分割,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-01-01
  • C++實(shí)現(xiàn)LeetCode數(shù)組練習(xí)題

    C++實(shí)現(xiàn)LeetCode數(shù)組練習(xí)題

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode的幾道數(shù)組練習(xí)題,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • Matlab利用遺傳算法GA求解非連續(xù)函數(shù)問題詳解

    Matlab利用遺傳算法GA求解非連續(xù)函數(shù)問題詳解

    遺傳算法起源于對生物系統(tǒng)所進(jìn)行的計(jì)算機(jī)模擬研究。其本質(zhì)是一種高效、并行、全局搜索的方法,能在搜索過程中自動(dòng)獲取和積累有關(guān)搜索空間的知識(shí),并自適應(yīng)地控制搜索過程以求得最佳解。本文將利用其求解非連續(xù)函數(shù)問題,需要的可以參考一下
    2022-09-09
  • Qt實(shí)現(xiàn)小功能之圓形進(jìn)度條的方法詳解

    Qt實(shí)現(xiàn)小功能之圓形進(jìn)度條的方法詳解

    在Qt自帶的控件中,只有垂直進(jìn)度條、水平進(jìn)度條兩種。在平時(shí)做頁面開發(fā)時(shí),有些時(shí)候會(huì)用到圓形進(jìn)度條,比如說:下載某個(gè)文件的下載進(jìn)度。本文就來實(shí)現(xiàn)一個(gè)圓形進(jìn)度條,需要的可以參考一下
    2022-10-10
  • C++中訪問權(quán)限的示例詳解

    C++中訪問權(quán)限的示例詳解

    C++通過 public、protected、private 三個(gè)關(guān)鍵字來控制成員變量和成員函數(shù)的訪問權(quán)限(也稱為可見性),下面這篇文章主要給大家介紹了關(guān)于C++中訪問權(quán)限的相關(guān)資料,需要的朋友可以參考下
    2021-07-07
  • MATLAB Delaunay算法提取離散點(diǎn)邊界的方法

    MATLAB Delaunay算法提取離散點(diǎn)邊界的方法

    這篇文章主要為大家詳細(xì)介紹了MATLAB Delaunay算法提取離散點(diǎn)邊界的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-12-12

最新評論