淺談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++代碼就會越來越困難。
閱讀更多 掌趣網絡 的文章