自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C++中列表初始化,你知多少?

開發(fā) 前端
雖然列表初始化是一種很便捷和安全的初始化方式,但在某些情況下,特別是對于非聚合類型和可能導(dǎo)致 most vexing parse 的地方,可能需要考慮其他的初始化方式。

一、何為列表初始化

C++中的列表初始化是一種用一對花括號(hào) {} 來進(jìn)行對象初始化的語法。它被引入主要是為了提供一種統(tǒng)一的初始化方式,適用于各種不同的數(shù)據(jù)類型和數(shù)據(jù)結(jié)構(gòu),包括基本類型、數(shù)組、結(jié)構(gòu)體、類、STL 容器等。列表初始化在 C++11 標(biāo)準(zhǔn)中被引入,是現(xiàn)代 C++ 編程風(fēng)格的一部分。

基本語法

Type variable = {value1, value2, ...};
  • 使用一對花括號(hào) {} 來初始化對象。
  • 列表初始化對于類型轉(zhuǎn)換更為嚴(yán)格,不允許縮窄轉(zhuǎn)換(請看下面何為窄轉(zhuǎn)化部分)。

示例

  • 基本類型:
int x = {42};
double y = {3.14};
  • 數(shù)組:
int arr[] = {1, 2, 3, 4, 5};
  • 結(jié)構(gòu)體:
struct Point {
    int x;
    int y;
};

Point p = {10, 20};
  • 類:
class MyClass {
public:
    int data;
    double value;

    MyClass(int d, double v) : data(d), value(v) {}
};

MyClass obj = {42, 3.14};
  • STL 容器:
#include <vector>
#include <map>

std::vector<int> vec = {1, 2, 3, 4, 5};
std::map<int, std::string> myMap = {{1, "one"}, {2, "two"}};
  • 自定義類型:
class MyType {
public:
    int x;
    double y;

    MyType(int a, double b) : x(a), y(b) {}
};

MyType myVar = {5, 2.5};

二、何為窄轉(zhuǎn)化

窄轉(zhuǎn)化(Narrowing Conversion)指的是將一個(gè)具有較大范圍的值轉(zhuǎn)換為較小范圍的類型時(shí)可能丟失信息的情況。這種轉(zhuǎn)換可能導(dǎo)致截?cái)嗷蚴д?,因?yàn)槟繕?biāo)類型的表示范圍比源類型小。在 C++ 中,窄轉(zhuǎn)化是一種不安全的類型轉(zhuǎn)換,因?yàn)樗赡軐?dǎo)致數(shù)據(jù)丟失或意外的行為。

以下是一些示例說明窄轉(zhuǎn)化:

  • 從浮點(diǎn)數(shù)到整數(shù):
double myDouble = 3.14;
int myInt = myDouble; // 窄轉(zhuǎn)化,可能會(huì)截?cái)嘈?shù)部分
  • 從長整型到整數(shù):
long long myLong = 1000000000000;
int myInt = myLong; // 窄轉(zhuǎn)化,可能會(huì)截?cái)嗷蛞绯?/code>
  • 從大范圍的整數(shù)類型到小范圍的整數(shù)類型:
long long myLong = 1000000000000;
int myInt = static_cast<int>(myLong); // 窄轉(zhuǎn)化,可能會(huì)截?cái)嗷蛞绯?/code>

窄轉(zhuǎn)化是需要小心處理的,因?yàn)樗赡軐?dǎo)致數(shù)據(jù)的損失和不確定的行為。在需要進(jìn)行類型轉(zhuǎn)換時(shí),最好使用安全的轉(zhuǎn)換方式,例如使用 static_cast 并在可能丟失信息的地方進(jìn)行顯式的檢查和處理。在 C++11 引入的列表初始化中,提供了對縮窄轉(zhuǎn)換的更嚴(yán)格的檢查,不允許在列表初始化時(shí)發(fā)生縮窄轉(zhuǎn)換,從而幫助程序員避免潛在的問題。

三、列表初始化規(guī)則和特點(diǎn)

列表初始化有一些規(guī)則和特點(diǎn),主要包括以下幾個(gè)方面:

1. 不允許縮窄轉(zhuǎn)換

列表初始化對類型轉(zhuǎn)換更為嚴(yán)格,不允許發(fā)生縮窄轉(zhuǎn)換,即不允許將一個(gè)精度更高的類型賦值給一個(gè)精度較低的類型。

int x = {3.14}; // 錯(cuò)誤,嘗試縮窄轉(zhuǎn)換

2. 對于數(shù)組,列表初始化的大小由元素個(gè)數(shù)決定

int arr[] = {1, 2, 3}; // 合法,數(shù)組大小為3

3. 類型不匹配時(shí)可能調(diào)用構(gòu)造函數(shù)

當(dāng)列表初始化的類型和目標(biāo)類型不匹配時(shí),如果存在適當(dāng)?shù)臉?gòu)造函數(shù),編譯器會(huì)嘗試調(diào)用構(gòu)造函數(shù)進(jìn)行初始化。

class MyClass {
public:
    int data;
    double value;

    MyClass(int d, double v) : data(d), value(v) {}
};

MyClass obj = {42, 3.14}; // 合法,調(diào)用構(gòu)造函數(shù)

4. 空列表初始化

在某些情況下,可以使用空的花括號(hào) {} 進(jìn)行初始化,這會(huì)被解釋為對應(yīng)類型的默認(rèn)值。

int x = {}; // x 被初始化為 0
double y = {}; // y 被初始化為 0.0

5. 對于類類型,構(gòu)造函數(shù)的匹配規(guī)則

當(dāng)進(jìn)行列表初始化時(shí),編譯器會(huì)根據(jù)構(gòu)造函數(shù)的參數(shù)匹配規(guī)則選擇相應(yīng)的構(gòu)造函數(shù)。

class Example {
public:
    Example(int a, double b);
    Example(std::string str);
};

Example obj1 = {42, 3.14};  // 調(diào)用構(gòu)造函數(shù) Example(int, double)
Example obj2 = {"Hello"};    // 調(diào)用構(gòu)造函數(shù) Example(std::string)

6. 嵌套初始化

可以使用嵌套的列表初始化來初始化嵌套的數(shù)據(jù)結(jié)構(gòu)。

std::vector<std::vector<int>> matrix = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};

總體來說,列表初始化提供了一種簡潔且直觀的初始化語法,同時(shí)對類型匹配和轉(zhuǎn)換有著更為嚴(yán)格的規(guī)定,減少了一些初始化時(shí)可能發(fā)生的錯(cuò)誤。

四、列表初始化的好處

列表初始化(Uniform Initialization)在 C++ 中引入的好處主要有以下幾點(diǎn):

  • 一致性:列表初始化提供了一種一致的初始化語法,可以用于初始化各種類型的對象,包括基本類型、數(shù)組、結(jié)構(gòu)體、類、STL 容器等。這種一致性使得代碼更加清晰和易讀。
int x = {42};             // 初始化基本類型
int arr[] = {1, 2, 3};    // 初始化數(shù)組
Point p = {10, 20};       // 初始化結(jié)構(gòu)體
MyClass obj = {42, 3.14};  // 初始化類
std::vector<int> vec = {1, 2, 3}; // 初始化容器
  • 防止窄化轉(zhuǎn)換:列表初始化對類型轉(zhuǎn)換更為嚴(yán)格,不允許發(fā)生縮窄轉(zhuǎn)換,從而減少了一些可能引入 bug 的情況。
int x = {3.14}; // 錯(cuò)誤,嘗試縮窄轉(zhuǎn)換
  • 構(gòu)造函數(shù)匹配:當(dāng)進(jìn)行列表初始化時(shí),如果存在適當(dāng)?shù)臉?gòu)造函數(shù),編譯器會(huì)嘗試調(diào)用構(gòu)造函數(shù)進(jìn)行初始化。這提高了代碼的靈活性,使得用戶定義的類型更容易進(jìn)行初始化。
class MyClass {
public:
    int data;
    double value;

    MyClass(int d, double v) : data(d), value(v) {}
};

MyClass obj = {42, 3.14}; // 調(diào)用構(gòu)造函數(shù)
  • 簡潔性:列表初始化的語法相對簡潔,通過一對花括號(hào){}就可以完成初始化,避免了傳統(tǒng)的各種初始化方式可能導(dǎo)致的歧義。
int arr[] = {1, 2, 3};  // 合法,簡潔
  • 避免 most vexing parse: 傳統(tǒng)的初始化語法在某些情況下可能會(huì)導(dǎo)致 most vexing parse,而列表初始化語法避免了這一問題。

"Most Vexing Parse" 是一個(gè)有趣而令人困擾的 C++ 編程問題,它通常發(fā)生在類的對象聲明上,導(dǎo)致程序員可能不是按照他們預(yù)期的方式初始化對象。這個(gè)問題的名字來源于這種情況的令人迷惑和難以理解。

Most Vexing Parse 主要發(fā)生在下面這樣的情況:

class MyClass {
public:
    MyClass() {}
};

int main() {
    MyClass obj();  // 最令人迷惑的解析,聲明了一個(gè)函數(shù)而不是對象
    // ...
    return 0;
}

在上述代碼中,MyClass obj(); 被編譯器解釋為聲明一個(gè)返回 MyClass 類型的函數(shù)而不是創(chuàng)建一個(gè) MyClass 類型的對象。這是因?yàn)樵?C++ 中,如果聲明一個(gè)函數(shù)的時(shí)候帶有空括號(hào),編譯器會(huì)將其解釋為一個(gè)函數(shù)聲明而不是一個(gè)對象定義。

為了避免 most vexing parse,可以使用以下兩種方式之一:

  • 使用花括號(hào)初始化:
MyClass obj{};  // 使用花括號(hào)初始化,避免 most vexing parse
  • 使用括號(hào)初始化:
MyClass obj();  // 編譯器會(huì)將其解釋為函數(shù)聲明
MyClass obj{};  // 使用括號(hào)初始化,避免 most vexing parse

這個(gè)問題是由 C++ 語法規(guī)則引起的,對于初學(xué)者來說可能會(huì)令人困擾。因此,在聲明和初始化對象時(shí),特別是在有可能發(fā)生 most vexing parse 的地方,建議使用花括號(hào)初始化或括號(hào)初始化,以避免潛在的問題。

五、不適用列表初始化的情況

什么是聚合類型

1、類型是一個(gè)普通數(shù)組,如int[5],char[],double[]等 

2、類型是一個(gè)類,且滿足以下條件:

  • 沒有用戶聲明的構(gòu)造函數(shù)
  • 沒有用戶提供的構(gòu)造函數(shù)(允許顯示預(yù)置或棄置的構(gòu)造函數(shù))
  • 沒有私有或保護(hù)的非靜態(tài)數(shù)據(jù)成員
  • 沒有基類
  • 沒有虛函數(shù)
  • 沒有{}和=直接初始化的非靜態(tài)數(shù)據(jù)成員
  • 沒有默認(rèn)成員初始化器

雖然列表初始化是一種很方便和清晰的初始化方式,但有一些情況下不適合或者不能使用列表初始化:

  • 不支持聚合初始化的類列表初始化主要用于聚合類型的初始化,而對于不支持聚合初始化的類,不能使用列表初始化。一個(gè)類如果有用戶自定義的構(gòu)造函數(shù)、私有/受保護(hù)的非靜態(tài)數(shù)據(jù)成員,或者基類沒有默認(rèn)構(gòu)造函數(shù),那么該類就不再是聚合類型。
class NotAggregate {
public:
    int x;
    int y;

    NotAggregate(int a, int b) : x(a), y(b) {}
};

NotAggregate obj = {1, 2}; // 錯(cuò)誤,NotAggregate 不是聚合類型
  • 不能進(jìn)行窄化轉(zhuǎn)換的地方:列表初始化不允許發(fā)生窄化轉(zhuǎn)換,因此在需要執(zhí)行窄化轉(zhuǎn)換的地方不能使用列表初始化。
double myDouble = 3.14;
int myInt = myDouble; // 合法,但列表初始化會(huì)報(bào)錯(cuò)
  • 需要避免 most vexing parse 的地方:在可能發(fā)生 most vexing parse(最令人迷惑的解析)的地方,列表初始化可能不適用。這通常發(fā)生在類的默認(rèn)構(gòu)造函數(shù)被誤解為函數(shù)聲明的情況下。
class MyClass {
public:
    MyClass() {}
};

MyClass obj();   // 最令人迷惑的解析,聲明了一個(gè)函數(shù)而不是對象
MyClass obj{};   // 正確的初始化方式

總之,雖然列表初始化是一種很便捷和安全的初始化方式,但在某些情況下,特別是對于非聚合類型和可能導(dǎo)致 most vexing parse 的地方,可能需要考慮其他的初始化方式。

責(zé)任編輯:武曉燕 來源: Linux兵工廠
相關(guān)推薦

2023-11-12 23:08:17

C++初始化

2010-02-01 14:21:24

C++初始化列表

2023-10-06 20:57:52

C++聚合成員

2010-02-06 14:40:50

C++初始化和賦值

2020-10-12 09:49:14

C++ 開發(fā)代碼

2011-06-09 14:13:06

C++JAVA缺省初始化

2011-06-17 15:29:44

C#對象初始化器集合初始化器

2010-02-05 17:16:05

C++構(gòu)造函數(shù)

2010-02-06 15:58:10

C++集合初始化

2024-08-08 16:34:16

C++11編程

2021-12-26 00:08:35

C++初始化列表

2010-02-03 11:01:18

C++類靜態(tài)成員初始化

2023-12-04 10:57:52

函數(shù)C++

2009-07-31 17:51:27

C#對象初始化

2009-09-18 11:15:52

C#數(shù)組初始化

2019-11-04 13:50:36

Java數(shù)組編程語言

2016-01-28 19:58:43

創(chuàng)業(yè)IT建設(shè)

2020-06-08 07:00:00

數(shù)據(jù)安全加密機(jī)密計(jì)算

2010-02-06 10:24:48

C++二維數(shù)組初始化

2024-12-25 07:00:00

聚合初始化C++
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)