浅谈initialize_list原理
自从C++11 开始,初始化就引入了一个新的特性,如下:
可以直接通过一个初始化列表来初始化容器,那么这个是怎么实现的呢?这就和我们今天要说的initializer_list有关了。
1. 引入
先看一个情况,在C语言中,如果我们想要实现一个可变形参的函数,那么应该这么做:
这里函数必须声明称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:
从这里我们可以知道,这种类型是编译器自动构造的。
2.2 基本使用
这个类提供了如下的操作接口
关于构造函数,我们有如下构造方法:
1.initializer_list
2.initializer_list
2.3 示例
那么 initializer_list具体怎么使用呢?下面给出一个基本的使用例子:
2.4 原理
先看一下initializer_list的实现过程:
从这里我们可以发现如下问题:
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
最好的办法就是看看反汇编代码,在VS编译器中(每个编译器的实现可能会不同):
原理为:
1.在栈上面分配一个数组。
2.取到数组的第一个和最后一个地址的下一个(ebp-18h, ebp-2Ch).
3.然后调用构造函数initializer_list(const _Elem *_First_arg, const _Elem *_Last_arg) noexcept。
也就是说,编译器底层帮忙做了所有的事情。
唉,有人说C++真的很难,我觉得编译器做了太多的事情,也是导致C++难学的原因;因为编译器做得事情越多,使用起来就会越方便,但是理解起来就更加困难。
3. 应用
3.1 容器的使用
在vector中存在如下的构造函数
那么,我们就可以使用:
编译器帮我们做得事情:
3.2 项目使用
我们可以在自己的类或者函数中实现这一个特性,例如:
反汇编结果如下:
4. 总结
C++编译器总是瞒着我们做了太多的事情,所有导致我们知其然而不知其所以然;导致我们C++使用越来越简单,理解起来就会越来越复杂;导致我们编写C++越来越简单,但是写出高效的C++代码就会越来越困难。
本文来自投稿,不代表本人立场,如若转载,请注明出处:http://www.souzhinan.com/kj/251540.html