镇楼图
来看看源码:
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;
// The compiler can call a private constructor.
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) { }
// Number of elements.
constexpr size_type
size() const noexcept { return _M_len; }
// First element.
constexpr const_iterator
begin() const noexcept { return _M_array; }
// One past the last element.
constexpr const_iterator
end() const noexcept { return begin() + size(); }
};
initializer_list是系统自定义的类模板:
template
class initializer_list;
该类模板中主要有三个方法:
- begin()
- end()
- 获取区间中元素个数的方法size()
下面的话援引cppreference上的介绍
本人英语不好,但是重点我会拿红色标记出来,耐心读几句英语胜过看一大堆中文博客:
Defined in header
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:
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.
这句不知道啥意思
来张图一目了然:
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 }; // the type of il is an initializer_list
简单来说,当编译器识别到右值是用花括号括起来的逗号分隔的元素列表时,编译器就会自动构造一个临时数组来存放花括号里的值
接着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);
}
}
// std::initializer_list support -*- C++ -*-
// Copyright (C) 2008-2017 Free Software Foundation, Inc.
//
// This file is part of GCC.
//
// GCC is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3, or (at your option)
// any later version.
//
// GCC is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// Under Section 7 of GPL version 3, you are granted additional
// permissions described in the GCC Runtime Library Exception, version
// 3.1, as published by the Free Software Foundation.
// You should have received a copy of the GNU General Public License and
// a copy of the GCC Runtime Library Exception along with this program;
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// .
/** @file initializer_list
* This is a Standard C++ Library header.
*/
#ifndef _INITIALIZER_LIST
#define _INITIALIZER_LIST
#pragma GCC system_header
#if __cplusplus < 201103L
# include
#else // C++0x
#pragma GCC visibility push(default)
#include
namespace std
{
/// initializer_list
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;
// The compiler can call a private constructor.
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) { }
// Number of elements.
constexpr size_type
size() const noexcept { return _M_len; }
// First element.
constexpr const_iterator
begin() const noexcept { return _M_array; }
// One past the last element.
constexpr const_iterator
end() const noexcept { return begin() + size(); }
};
/**
* @brief Return an iterator pointing to the first element of
* the initializer_list.
* @param __ils Initializer list.
*/
template<class _Tp>
constexpr const _Tp*
begin(initializer_list<_Tp> __ils) noexcept
{ return __ils.begin(); }
/**
* @brief Return an iterator pointing to one past the last element
* of the initializer_list.
* @param __ils Initializer list.
*/
template<class _Tp>
constexpr const _Tp*
end(initializer_list<_Tp> __ils) noexcept
{ return __ils.end(); }
}
#pragma GCC visibility pop
#endif // C++11
#endif // _INITIALIZER_LIST