【C++11】深挖列表初始化、initializer_list

镇楼图

【C++11】深挖列表初始化、initializer_list_第1张图片

  • 目录
  • 1.核心源码剖析
  • 2.使用介绍
  • 3.完整源码

核心源码剖析

来看看源码:

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上的介绍

本人英语不好,但是重点我会拿红色标记出来,耐心读几句英语胜过看一大堆中文博客:

std::initializer_list

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:

  • 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.

这句不知道啥意思

来张图一目了然:

【C++11】深挖列表初始化、initializer_list_第2张图片


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 };  // 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);
    }
}

initializer_list完整源码

// 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

你可能感兴趣的:(C++,c++,开发语言)