C++11之列表初始化,以及initializer_list简介

发布于:2025-07-19 ⋅ 阅读:(15) ⋅ 点赞:(0)


在这里插入图片描述

一.列表初始化

在 C++11 标准中,列表初始化(Uniform Initialization)作为一种全新的初始化方式,为 C++ 编程带来了显著的变革。它不仅让代码更加简洁易读,还提升了语言的表达能力和灵活性。

一、列表初始化简介

列表初始化是一种使用花括号 {} 来初始化对象的语法形式,其基本形式如下:

Type obj = {value1, value2, ...};

或者

Type obj{value1, value2, ...};

这种方式可以用于初始化各种类型的对象,包括内置类型、类类型、数组等。它旨在提供一种统一的初始化语法,以解决传统初始化方式中存在的问题,如初始化方式不一致、类型安全问题等。

(一)初始化内置类型

对于内置类型,如 intfloat 等,列表初始化会进行值初始化。例如:

int a = {5}; // 等价于 int a(5);
float b{3.14f}; // 等价于 float b(3.14f);

如果初始化列表中包含多个值,编译器会报错,因为内置类型只能接受一个初始化值。

(二)类对象

对于类对象,列表初始化可以直接初始化类的成员变量。例如:

class Person {
public:
    std::string name;
    int age;
};

Person p{"zzh", 18}; // 使用列表初始化

在上述代码中,Person 类有两个成员变量 nameage,我们使用列表初始化的方式直接初始化了这两个成员变量,这种方式非常直观和方便。

(三)初始化数组

列表初始化可以方便地初始化数组,包括静态数组和动态数组。例如:

int arr[] = {1, 2, 3, 4}; // 静态数组
int* dynArr = new int[4]{1, 2, 3, 4}; // 动态数组

如果初始化列表中的元素个数少于数组的大小,剩余的元素会被初始化为零。

(四)初始化标准库容器

列表初始化可以用于初始化标准库容器,如 std::vectorstd::map 等。例如:

std::vector<int> vec{1, 2, 3, 4};
std::map<int, std::string> map{{1, "one"}, {2, "two"}};

这种方式不仅简洁,还避免了逐个插入元素的繁琐操作。

二、列表初始化的规则

(一)直接初始化与列表初始化

列表初始化和直接初始化在某些情况下可能会产生不同的结果。例如:

struct A {
    A(int) {}
};

struct B {
    B(std::initializer_list<int>) {}
};

A a1(1); // 直接初始化,调用 A(int)
A a2{1}; // 列表初始化,报错,因为 A 没有接受 initializer_list 的构造函数

B b1(1); // 报错,因为 B 没有接受 int 的构造函数
B b2{1}; // 列表初始化,调用 B(std::initializer_list<int>)

在使用列表初始化时,编译器会优先查找接受 initializer_list 的构造函数。如果没有找到,会尝试匹配其他构造函数。

(二)列表初始化的限制

  • 内置类型:内置类型只能接受一个初始化值。如果初始化列表中包含多个值,编译器会报错。
  • 类类型:如果类定义了接受 initializer_list 的构造函数,会优先调用该构造函数。如果没有找到合适的构造函数,编译器会报错。
  • 数组:如果初始化列表中的元素个数少于数组的大小,剩余的元素会被初始化为零。

(三)空列表初始化

空列表初始化是指使用空的花括号 {} 来初始化变量或对象。对于基本数据类型,空列表初始化会将变量初始化为零值。例如:

int a{}; // a 的值为 0
double b{}; // b 的值为 0.0

对于类对象,空列表初始化会调用默认构造函数。如果类没有默认构造函数,则会报错。例如:

class Test {
public:
    Test() { std::cout << "Default constructor called" << std::endl; }
};

Test t{}; // 调用默认构造函数

在上述代码中,Test 类有一个默认构造函数,因此空列表初始化会调用该默认构造函数。

二.initializer_list

在这里插入图片描述
在这里插入图片描述
C++11库中提出了⼀个std::initializer_list的类,这个类的本质是底层开⼀个数组,将数据拷⻉过来,std::initializer_list内部有两个指针分别指向数组的开始和结束。

initializer_list基本介绍

std::initializer_list 是一个模板类,用于表示初始化列表。它提供了一种方便的方式来处理一组同类型的数据。initializer_list 的对象可以通过花括号 {} 来创建,例如:

std::initializer_list<int> list = {1, 2, 3, 4};

或者直接在函数参数中使用:

void printList(std::initializer_list<int> list) {
    for (auto it : list) {
        std::cout << it << " ";
    }
}

printList({1, 2, 3, 4});

(一)特性

  • 只读性initializer_list 中的元素是只读的,不能被修改。这是因为 initializer_list 是一个轻量级的包装器,它并不真正拥有数据,而是指向原始的初始化列表。
  • 迭代器支持initializer_list 提供了迭代器支持,可以通过迭代器来访问其中的元素。例如:
std::initializer_list<int> list = {1, 2, 3, 4};
for (auto it = list.begin(); it != list.end(); ++it) {
    std::cout << *it << " ";
}
  • 大小查询:可以通过 size() 方法来获取 initializer_list 中的元素个数。例如:
std::initializer_list<int> list = {1, 2, 3, 4};
std::cout << "Size: " << list.size() << std::endl;

(二)应用

  • 构造函数初始化:类可以通过接受 initializer_list 参数的构造函数来初始化其成员变量。例如:
class Vector {
private:
    std::vector<int> data;
public:
    Vector(std::initializer_list<int> list) : data(list) {}
};

Vector vec{1, 2, 3, 4}; // 初始化 Vector 对象

容器⽀持⼀个std::initializer_list的构造函数,也就⽀持任意多个值构成{x1,x2,x3…} 进⾏初始化。STL中的容器⽀持任意多个值构成的 {x1,x2,x3…} 进⾏初始化,就是通过std::initializer_list的构造函数⽀持的。

  • 函数参数:函数可以接受 initializer_list 参数,从而方便地处理一组数据。例如:
void printList(std::initializer_list<int> list) {
    for (auto it : list) {
        std::cout << it << " ";
    }
}

printList({1, 2, 3, 4});

(三)initializer_list 的生命周期

initializer_list 的生命周期与初始化列表的生命周期相同,即在初始化列表的作用域结束后,initializer_list 也会失效。因此,不能将 initializer_list 的引用存储起来,否则会导致未定义行为。

三、列表初始化与 initializer_list 的优势

(一)代码简洁性

列表初始化和 initializer_list 的使用让代码更加简洁易读。例如,初始化一个数组或类对象时,不再需要逐个赋值,而是可以直接使用花括号 {} 来完成初始化。

(二)类型安全

列表初始化会进行严格的类型检查,避免了类型不匹配的问题。例如,如果初始化列表中的值类型与目标类型不匹配,编译器会报错。

(三)灵活性

initializer_list 提供了灵活的方式来处理一组数据,可以通过迭代器、大小查询等方式来操作数据。

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到