list初始化_浅谈C++ initialize_list原理

浅谈initialize_list原理

自从C++11 开始,初始化就引入了一个新的特性,如下:

4bfe9aac111d45b59e9d8b2b6cb37561.png

​可以直接通过一个初始化列表来初始化容器,那么这个是怎么实现的呢?这就和我们今天要说的initializer_list有关了。

1. 引入

先看一个情况,在C语言中,如果我们想要实现一个可变形参的函数,那么应该这么做:

d3f0d19f1ef051e8c9dd9210b596e6c6.png

​这里函数必须声明称C调用约定,至于原因,跟栈平衡恢复有关,这里不细讲。

当然在C++中,也可以使用这种情况,不过C++可以使用另外一种技术实现,就是initializer_list,下面我们看一下这种技术的基本使用和原理。

2. initializer_list

2.1 简介

先来看一下C++网站对于这种结构的描述:

This type is used to access the values in a C++ initialization list, which is a list of elements of type const T.

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:

3c76d99fda0560cc6d3036a8cd433d98.png

​从这里我们可以知道,这种类型是编译器自动构造的。

2.2 基本使用

这个类提供了如下的操作接口

8d5d2e82671bbbc782e7e53d1f718b6b.png

​关于构造函数,我们有如下构造方法:

1.initializer_list li : 构造一个空的列表。

2.initializer_list li{a, b, c, ...} : 构造一个指定的列表。

2.3 示例

那么 initializer_list具体怎么使用呢?下面给出一个基本的使用例子:

aead72bed903664aff393d560da271c1.png

​2.4 原理

先看一下initializer_list的实现过程:

d2ecadb1ab0e8165000946432124696d.png
88ee140deb9fb9ae80263fc10e2f1f17.png

​从这里我们可以发现如下问题:

1.保存const的变量的指针(起始和结束)。

2.构造函数initializer_list() noexcept.

3.构造函数initializer_list(const _Elem *_First_arg, const _Elem *_Last_arg) noexcept

4.initializer_list保存的元素应该是一样的。

从上分析,initializer_list没有类似initializer_list(int, int, int, ...)的构造函数,那么对于initializer_list li = {100, 200, 300, 400, 500}是怎么初始化的呢?

最好的办法就是看看反汇编代码,在VS编译器中(每个编译器的实现可能会不同):

cf2ea9eeb3127ca39e2beef25f3f15ae.png

​原理为:

1.在栈上面分配一个数组。

2.取到数组的第一个和最后一个地址的下一个(ebp-18h, ebp-2Ch).

3.然后调用构造函数initializer_list(const _Elem *_First_arg, const _Elem *_Last_arg) noexcept。

也就是说,编译器底层帮忙做了所有的事情。

唉,有人说C++真的很难,我觉得编译器做了太多的事情,也是导致C++难学的原因;因为编译器做得事情越多,使用起来就会越方便,但是理解起来就更加困难。

3. 应用

3.1 容器的使用

在vector中存在如下的构造函数

aab72ed88b680d384c22530a14a0018f.png

​那么,我们就可以使用:

a8ae775185de7d68f0aa19a03b784ccf.png

​编译器帮我们做得事情:

2d20106f76da5bee151b7986dad61588.png

​3.2 项目使用

我们可以在自己的类或者函数中实现这一个特性,例如:

d5e5fc9dfdb7eaa018627567c4f5a724.png

​反汇编结果如下:

b13cb9ed2dbe0503818eeaf1b6e881d3.png

​4. 总结

C++编译器总是瞒着我们做了太多的事情,所有导致我们知其然而不知其所以然;导致我们C++使用越来越简单,理解起来就会越来越复杂;导致我们编写C++越来越简单,但是写出高效的C++代码就会越来越困难。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值