简介
std::initializer_list 是C++11提供的新类型,是一个访问 const T 类型对象数组的轻量代理对象,是一个模板类
类模板
1 2
| template< class T > class initializer_list;
|
自动构造
以下情况下 initializer_list 会自动构造:
1. 用花括号初始化器列表列表初始化一个对象,其中对应构造函数接受一个 std::initializer_list 参数
1 2 3 4 5 6 7 8 9 10 11
| template< class T > class Soul { public: vector<T> v; Soul(initializer_list<T> l) : v(l) {}; }; int main() { Soul<int> s{1, 2, 3, 4, 5}; }
|
构造时反汇编为:
1 2 3
| ... 00007FF7F5004BE6 call std::initializer_list<int>::initializer_list<int> (07FF7F500143Dh) ...
|
由此可以看出调用了 initalizer_list 的自动构造
2. 以花括号初始化器列表为赋值的右运算数,或函数调用参数,而对应的赋值运算符/函数接受 std::initializer_list 参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| template< class T > class Soul { public: vector<T> v; void append(initializer_list<T> l) { for (auto i = std::begin(l); i != std::end(l); ++i) v.push_back(*i); } }; int main() { Soul<int> s; s.append({ 1,2,3,4,5 }); }
|
s.append部分反汇编为:
1 2 3
| ... 00007FF7F0B6900B call std::initializer_list<int>::initializer_list<int> (07FF7F0B6143Dh) ...
|
由此可以看出调用了 initalizer_list 的自动构造
3. 绑定花括号初始化器列表到 auto ,包括在范围 for 循环中
1 2 3 4
| for(auto i : {1, 2, 3, 4, 5}) { }
|
for 循环部分反汇编为:
1 2 3 4 5 6 7
| ... 00007FF76F5E92DD call std::initializer_list<int>::initializer_list<int> (07FF76F5E143Dh) ... 00007FF76F5E92EE call std::initializer_list<int>::begin (07FF76F5E15D7h) ... 00007FF76F5E92FE call std::initializer_list<int>::end (07FF76F5E1708h) ...
|
由此可以看出调用了 initalizer_list 的自动构造
成员函数
- size() - 返回 initializer_list 中的元素数目
- begin() - 返回指向首元素的指针
- end() - 返回指向末元素后一位置的指针
非成员函数
对 std::initializer_list 重载的自由函数模板
- std::rbegin() (C++14)
- std::rend() (C++14)
- std::crbegin() (C++14)
- std::crend() (C++14)
- std::empty() (C++17)
- std::data() - 获得指向底层数组的指针,但返回的指针为 const (C++17)
initalizer_list 原理分析
首先看 initalizer_list 的构造函数
1 2 3 4 5 6
| constexpr initializer_list(const _Elem *_First_arg, const _Elem *_Last_arg) noexcept : _First(_First_arg), _Last(_Last_arg) { } }
|
从上分析,initializer_list没有类似initializer_list(int, int, int, …)的构造函数,那么对于initializer_list li = { 1, 2, 3, 4, 5, 6 }是怎么初始化的呢
查看其反汇编(此处为vs-v141-x64)
1 2 3 4 5 6 7 8 9 10 11 12
| initializer_list<int> l = { 1,2,3,4,5,6 }; 00007FF69B7F1D7B mov dword ptr [rbp+38h],1 00007FF69B7F1D82 mov dword ptr [rbp+3Ch],2 00007FF69B7F1D89 mov dword ptr [rbp+40h],3 00007FF69B7F1D90 mov dword ptr [rbp+44h],4 00007FF69B7F1D97 mov dword ptr [rbp+48h],5 00007FF69B7F1D9E mov dword ptr [rbp+4Ch],6 00007FF69B7F1DA5 lea rax,[rbp+50h] 00007FF69B7F1DA9 mov r8,rax 00007FF69B7F1DAC lea rdx,[rbp+38h] 00007FF69B7F1DB0 lea rcx,[l] 00007FF69B7F1DB4 call std::initializer_list<int>::initializer_list<int> (07FF69B7F143Dh)
|
可以看出其原理为:
- 在栈上分配一个数组
- 获得数组其首地址和最后一个地址的下一位[ rbp+50h, rbp+38h ],栈上地址为由高到低
- 然后调用函数
initializer_list(const _Elem *_First_arg, const _Elem *_Last_arg) noexcept