镇楼图
核心源码剖析
来看看源码:
template<class _E>
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;
constexpr initializer_list(const_iterator __a, size_type __l)
: _M_array(__a), _M_len(__l) { }
public:
constexpr initializer_list() noexcept
: _M_array(0), _M_len(0) { }
constexpr size_type
size() const noexcept { return _M_len; }
constexpr const_iterator
begin() const noexcept { return _M_array; }
constexpr const_iterator
end() const noexcept { return begin() + size(); }
};
initializer_list是系统自定义的类模板: template<class T> class initializer_list; 该类模板中主要有三个方法:
- begin()
- end()
- 获取区间中元素个数的方法size()
下面的话援引cppreference上的介绍
本人英语不好,但是重点我会拿红色标记出来,耐心读几句英语胜过看一大堆中文博客:
std::initializer_list
Defined in header <initializer_list>
template< class T >
class initializer_list;
(since C++11)
An object of type std::initializer_list is a lightweight proxy object that provides access to an array of objects of type const T.
这边用了一个很有趣 的单词:proxy,是代理的意思;它告诉我们,initializer_list只不过是代理了另外一个底层数组(花括号列表初始化的一个临时数组),只是一个浅拷贝 罢了
A std::initializer_list object is automatically constructed when:
- a braced-init-list is used to list-initialize an object, where the corresponding constructor accepts an std::initializer_list parameter
- a braced-init-list is used as the right operand of assignment or as a function call argument, and the corresponding assignment operator/function accepts an std::initializer_list parameter
- a braced-init-list is bound to auto, including in a ranged for loop
Initializer lists may be implemented as a pair of pointers or pointer and length. Copying a std::initializer_list does not copy the underlying objects .
如果我们拷贝一个initializer_list ,我们做的只是拷贝了一个指针,只是一个浅拷贝
The underlying array is a temporary array of type const T[N], in which each element is copy-initialized (except that narrowing conversions are invalid) from the corresponding element of the original initializer list.
这句话是核心,这边的underlying array 翻译成底层数组 ,我们来看: 底层数组是const T[N]类型的临时数组,这个数组是复制了花括号{}列表的值构造出来的 这个数组也就是我们说的被initializer_list代理的数组
The lifetime of the underlying array is the same as any other temporary object, except that initializing an initializer_list object from the array extends the lifetime of the array exactly like binding a reference to a temporary (with the same exceptions, such as for initializing a non-static class member). The underlying array may be allocated in read-only memory.
这边的几句英文绕了,是说initializer_list 去代理临时数组就好比是去引用一个临时变量 由于临时数组的生命周期就在它花括号那一行,所以我们得用一个比如vector之类左值去接受(深拷贝)这个临时数组 换句话说,我们不能去把initializer_list做函数返回值,去return {1,2}
The program is ill-formed if an explicit or partial specialization of std::initializer_list is declared.
这句不知道啥意思
来张图一目了然:
initializer_list介绍
C++11中,vector可以用列表进行初始化:
vector<int> v = {1, 2, 3, 4};
这是为什么呢?
本质是在C++11中提供了initializer_list类,并且给vector添加了用initializer_list作为参数的构造函数,构造成员是不确定长度的同类型元素的对象
Objects of this type are automatically constructed by the compiler from initialization list declarations, which is a list of comma-separated elements enclosed in braces:
auto il = { 10, 20, 30 };
简单来说,当编译器识别到右值是用花括号括起来的逗号分隔的元素列表时,编译器就会自动构造一个临时数组来存放花括号里的值
接着initializer_list引用这个临时数组的地址,也就是说就initializer_list没有对于临时数组进行深拷贝,只是做了地址的浅拷贝
要使用这一新特性,只需要给对于的类增加带initializer_list参数的构造函数:
vector(initializer_list<T> l)
:_start(new T[l.size()])
, _finish(_start + l.size())
, _endOfStorage(_start + l.size())
{
for (size_t i = 0; i < l.size(); i++) {
_start[i] = *(l.begin() + i);
}
}
initializer_list完整源码
#ifndef _INITIALIZER_LIST
#define _INITIALIZER_LIST
#pragma GCC system_header
#if __cplusplus < 201103L
# include <bits/c++0x_warning.h>
#else
#pragma GCC visibility push(default)
#include <bits/c++config.h>
namespace std
{
template<class _E>
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;
constexpr initializer_list(const_iterator __a, size_type __l)
: _M_array(__a), _M_len(__l) { }
public:
constexpr initializer_list() noexcept
: _M_array(0), _M_len(0) { }
constexpr size_type
size() const noexcept { return _M_len; }
constexpr const_iterator
begin() const noexcept { return _M_array; }
constexpr const_iterator
end() const noexcept { return begin() + size(); }
};
template<class _Tp>
constexpr const _Tp*
begin(initializer_list<_Tp> __ils) noexcept
{ return __ils.begin(); }
template<class _Tp>
constexpr const _Tp*
end(initializer_list<_Tp> __ils) noexcept
{ return __ils.end(); }
}
#pragma GCC visibility pop
#endif
#endif
|