initializer_list是C++11提供的新类型。
特点:
1)用于实参类型相同的列表初始化。若实参的类型不同,可通过可变参数模板来实现。
2)initializer_list对象中的元素永远是常量值,我们无法改变initializer_list对象中元素的值。
template class initializer_list;
begin()提供一个指向列表首元素的指针,end()提供一个指向列表尾元素的下一个位置的指针。
struct myclass {
myclass (int,int);
myclass (initializer_list);
};
myclass foo {10,20}; // calls initializer_list ctor
myclass bar (10,20);
template
class initializer_list
{
public:
typedef _E value_type;
typedef const _E& reference;
typedef const _E& const_reference;
typedef size_t size_type;
typedef const _E* iterator;
typedef const _E* const_iterator;
private:
iterator _M_array; //迭代器变量
size_type _M_len; //长度
// The compiler can call a private constructor.
constexpr initializer_list(const_iterator __a, size_type __l)
: _M_array(__a), _M_len(__l) { } //构造函数为private
public:
constexpr initializer_list() noexcept
: _M_array(0), _M_len(0) { }
constexpr size_type size() const noexcept { return _M_len; } //被const修饰 只读
constexpr const_iterator begin() const noexcept { return _M_array; } //同上
constexpr const_iterator end() const noexcept { return begin() + size(); } //同上
};
initializer_list内部存储了两个变量:_M_array(迭代器变量)和_M_len(长度)。当用{}进行初始化的时候,首先会创建一个array,并将初始化元素存放起来。然后,调用initializer_list的构造函数,用array首元素的迭代器和array的元素个数,进行初始化。
1)initializer_list构造函数是private类型的,但在源码中有注明,编译器可以调用该private构造函数;
2)initializer_list是一个轻量级的容器类型,内部定义了iterator等容器必需的概念。其中有3个成员接口:size()、begin()和end()。遍历时取得的迭代器是只读的,无法修改其中的某一个元素的值;
3)对于initializer_list而言,它可以接收任意长度的初始化列表,但要求元素必须是同种类型T(或可转换为T);
4)initializer_list内部并不负责保存初始化列表中的元素拷贝,仅仅是列表中元素的引用而己。因此,通过拷贝构造对象与原对象共享列表中的元素空间。也就是说,initializer_list的内部并没有内含该array的内容,仅仅是拥有指向array的迭代器。如果拷贝构造或者拷贝赋值的话,array的内容只有一份,但有两份迭代器指向。如果对initializer_list对象copy一个副本,默认是浅拷贝,此时两个对象指向同一个array。这是危险的。
例如:
std::initializer_list func(void)
{
int a = 1, b = 2;
return {a, b}; //由于initializer_list保存的是对象的引用,但a与b是局部变量在
//func返回后会被释放,initializer_list内部会存在空悬指针!危险!
//正确的做法可以将返回值改为保存副本的容器,如vector
}
//注意下面s1、 s2、s3和s4均共享元素空间
initializer_list s1 = { "aa", "bb", "cc", "dd" };
initializer_list s2 = s1;
initializer_list s3(s1);
initializer_list s4;
s4 = s1;
#include
#include
#include
using namespace std;
template
class MyInitList {
std::vector v;
MyInitList (std::initializer_list l) : v(l)
{
cout << "constructed with a " << l.size() << endl;
}
void append(std::initializer_list l)
{
v.insert(v.end(), l.begin(), l.end());
}
std::pair c_arr() const
{
return{ &v[0], v.size() };
}
};
template
void templated_fn(T) {}
int main()
{
std::initializer_list lst{ 1,2,3,4,5 };
std::initializer_list lst1(lst);
std::initializer_list lst2 = lst;
cout << lst1.size() << endl;
cout << lst2.size() << endl;
//std::initializer_list lst4{ 1,2.2,3,"123" }; //error
for (auto itr = lst.begin(); itr != lst.end(); ++itr)
cout << *itr << " " << endl;
for (int i : {1, 2, 3})
{
cout << i << " ";
}
system("pause");
return 0;
}