C++11引入了一个新的类模板 initializer_list。
它本质就是C 的局部常量数组的封装,避免了使用因为动态数组或vector而产生的在堆上分配、释放内存的额外开销,同时提供begin(),end(),size()的接口可以配合STL的容器和算法,这样可以减少代码量,如:方便地设计出支持变长数组的函数。
initializer_list的成员都是const的,语法上不支持修改,减少出错概率。如两个initializer_list可以赋值,指向相同的数组。
与std::array<>比,initializer_list更灵活,不需要指定N,减少模板类导致的代码膨胀。
#include <initializer_list>
#include <iostream>
#include <vector>
#include <array>
using namespace std;
//方便的数组访问
void print(initializer_list<int> &l) {
cout << "size()=" << l.size() << endl;
int *p=(int*)l.begin();//不安全
*p = 888;
for (int i : l) cout << i << " ";
cout << endl;
}
//C数组访问需要传2个参数,容易出错
void print(int *a,int n) {
cout << "size()=" << n<<endl;
for (int i = 0; i < n;i++) cout << a[i] << " ";
cout << endl;
}
void print(int a[]) {
cout << "size()=" << a;
//int n = end(a) - begin(a);//error
//for (int i = 0; i < n; i++) cout << a[i] << " ";
cout << endl;
}
int main() {
#define DATA {1,2,3,4}
const int a[] = DATA;
int b[] = DATA;
auto l = DATA;//比数组定义还简单
auto l2 = l;//l2,l指向同一块内存
l2 = l;//l2,l指向同一块内存
int n = end(a) - begin(a);
cout << "&a=" << a << endl;
cout << "&b=" << b << endl;
cout << "i1.begin()=" << l.begin() << endl;
cout << "&l=" << (void*)&l << endl;
cout << "&l2=" << (void*)&l2 << endl;
cout << "&a-&b="<<(int*)&a- (int*)&b << endl;
cout << "&b-&l=" << (int*)&b - (int*)&l << endl;
cout << "&b-l.begin()=" << (const int*)&b - (const int*)(l.begin()) << endl;
cout << "&l2.begin()-l.begin()=" << (const int*)(l2.begin()) - (const int*)(l.begin()) << endl;
print(l);
//配合vector更方便
vector<int> v1(begin(a),end(a));
vector<int> v2(l);
return 0;
}
/*输出
通过比较指针可以看到initializer_list的内存和数组的内存很接近,因而分析出initializer_list的数据内存都是在栈上。
&a=0053FA54
&b=0053FA3C
i1.begin()=0053FA14
&l=0053FA2C
&l2=0053FA04
&a-&b=6
&b-&l=4
&b-l.begin()=10
&l2.begin()-l.begin()=0
size()=4
888 2 3 4
*/
initializer_list 的实现代码也非常简单(VS2017)。
// initializer_list standard header (core)
#pragma once
#ifndef _INITIALIZER_LIST_
#define _INITIALIZER_LIST_
#ifndef RC_INVOKED
#include <cstddef>
#pragma pack(push,_CRT_PACKING)
#pragma warning(push,_STL_WARNING_LEVEL)
#pragma warning(disable: _STL_DISABLED_WARNINGS)
_STL_DISABLE_CLANG_WARNINGS
#pragma push_macro("new")
#undef new
_STD_BEGIN
// CLASS TEMPLATE initializer_list
template<class _Elem>
class initializer_list
{ // list of pointers to elements
public:
typedef _Elem value_type;
typedef const _Elem& reference;
typedef const _Elem& const_reference;
typedef size_t size_type;
typedef const _Elem* iterator;
typedef const _Elem* const_iterator;
constexpr initializer_list() noexcept
: _First(nullptr), _Last(nullptr)
{ // empty list
}
constexpr initializer_list(const _Elem *_First_arg,
const _Elem *_Last_arg) noexcept
: _First(_First_arg), _Last(_Last_arg)
{ // construct with pointers
}
_NODISCARD constexpr const _Elem * begin() const noexcept
{ // get beginning of list
return (_First);
}
_NODISCARD constexpr const _Elem * end() const noexcept
{ // get end of list
return (_Last);
}
_NODISCARD constexpr size_t size() const noexcept
{ // get length of list
return (static_cast<size_t>(_Last - _First));
}
private:
const _Elem *_First;
const _Elem *_Last;
};
// FUNCTION TEMPLATE begin
template<class _Elem>
_NODISCARD constexpr const _Elem * begin(initializer_list<_Elem> _Ilist) noexcept
{ // get beginning of sequence
return (_Ilist.begin());
}
// FUNCTION TEMPLATE end
template<class _Elem>
_NODISCARD constexpr const _Elem * end(initializer_list<_Elem> _Ilist) noexcept
{ // get end of sequence
return (_Ilist.end());
}
_STD_END
#pragma pop_macro("new")
_STL_RESTORE_CLANG_WARNINGS
#pragma warning(pop)
#pragma pack(pop)
#endif /* RC_INVOKED */
#endif /* _INITIALIZER_LIST_ */
/*
* Copyright (c) by P.J. Plauger. All rights reserved.
* Consult your license regarding permissions and restrictions.
V6.50:0009 */