【導讀】:本文主要講解 C++ function 技術(shù)的實現(xiàn)與具體運用。
std::function是一個函數(shù)對象的包裝器,std::function的實例可以存儲,復(fù)制和調(diào)用任何可調(diào)用的目標,包括:
函數(shù)。
lamada表達式。
綁定表達式或其他函數(shù)對象。
指向成員函數(shù)和指向數(shù)據(jù)成員的指針。
當std::function對象沒有初始化任何實際的可調(diào)用元素,調(diào)用std::function對象將拋出std::bad_function_call異常。
本文我們來談一下std::function的實現(xiàn)原理。
1. std::function簡介
在討論其原理的時候,我們來熟悉一下這個東西是怎么使用的,C++標準庫詳細說明了這個的基本使用http://www.cplusplus.com/reference/functional/function/.
這里我們大概總結(jié)一下。
1.1 Member types
result_type | 返回類型 |
argument_type | 如果函數(shù)對象只有一個參數(shù),那么這個代表參數(shù)類型。 |
first_argument_type | 如果函數(shù)對象有兩個個參數(shù),那么這個代表第一個參數(shù)類型。 |
second_argument_type | 如果函數(shù)對象有兩個個參數(shù),那么這個代表第二個參數(shù)類型。 |
成員類型 | 說明 |
---|
1.2 Member functions
constructor | 構(gòu)造函數(shù):constructs a new std::function instance |
destructor | 析構(gòu)函數(shù):destroys a std::function instance |
operator= | 給定義的function對象賦值 |
operator bool | 檢查定義的function對象是否包含一個有效的對象 |
operator() | 調(diào)用一個對象 |
成員函數(shù)聲明 | 說明 |
---|
1.3 基本使用
#include
從上面我們可以發(fā)現(xiàn),std::function可以表示函數(shù),lamada,可調(diào)用類對象。
2. std::function實現(xiàn)
在標準庫中STL設(shè)計為如下:
template
上面的std::function繼承關(guān)系比較簡單,主要使用
union_Storage { //storageforsmallobjects(basic_stringissmall) max_align_t_Dummy1;//formaximumalignment char_Dummy2[_Space_size];//topermitaliasing _Ptrt*_Ptrs[_Num_ptrs];//_Ptrs[_Num_ptrs-1]isreserved };
這個來存儲我們設(shè)置的可調(diào)用對象,我們從std::function的使用過程看一下整個原理。
2.1 函數(shù)對象賦值
我們使用的時候一般使用f = Caller;來設(shè)置函數(shù)對象,我們看下這個的實現(xiàn)過程。
template
我們看this->_Reset(_Func)這個函數(shù),因為這個才是設(shè)置函數(shù)可調(diào)用對象的東西。
void_Set(_Ptrt*_Ptr)_NOEXCEPT {//storepointertoobject _Mystorage._Ptrs[_Num_ptrs-1]=_Ptr; } void_Reset_impl(_Fx&&_Val,const_Alloc&_Ax, _Myimpl*,_Alimpl&_Al,false_type) {//storecopyof_Valwithallocator,small(locallystored) _Myimpl*_Ptr=static_cast<_Myimpl?*>(_Getspace()); _Al.construct(_Ptr,_STDforward<_Fx>(_Val),_Ax); _Set(_Ptr); } template
這個代碼的主要意思就是創(chuàng)建一個_Func_impl<_Decayed, _Alloc, _Ret, _Types...>指針,然后賦值_Mystorage._Ptrs[_Num_ptrs - 1] = _Ptr;。
設(shè)置之后,我們看下調(diào)用操作怎么完成。
2.2 operator() 的實現(xiàn)
調(diào)用操作主要是通過operator()來實現(xiàn)的,我們看下這個的實現(xiàn)過程。
_Ptrt*_Getimpl()const_NOEXCEPT {//getpointertoobject return(_Mystorage._Ptrs[_Num_ptrs-1]); } _Retoperator()(_Types..._Args)const {//callthroughstoredobject if(_Empty()) _Xbad_function_call(); return(_Getimpl()->_Do_call(_STDforward<_Types>(_Args)...)); }
因此,我們是通過_Func_impl<_Decayed, _Alloc, _Ret, _Types...>轉(zhuǎn)發(fā)了調(diào)用操作_Do_call
2.3 _Func_impl的實現(xiàn)
class_Func_impl :public_Func_base<_Rx,?_Types...> {//derivedclassforspecificimplementationtypes public: typedef_Func_impl<_Callable,?_Alloc,?_Rx,?_Types...>_Myt; typedef_Func_base<_Rx,?_Types...>_Mybase; typedef_Wrap_alloc<_Alloc>_Myalty0; typedeftypename_Myalty0::templaterebind<_Myt>::other_Myalty; typedefis_nothrow_move_constructible<_Callable>_Nothrow_move; virtual_Rx_Do_call(_Types&&..._Args) {//callwrappedfunction return(_Invoke_ret(_Forced<_Rx>(),_Callee(), _STDforward<_Types>(_Args)...)); } _Compressed_pair<_Alloc,?_Callable>_Mypair; };
_Func_impl這個類通過_Do_call來轉(zhuǎn)發(fā)函數(shù)對象的調(diào)用操作。
3. 總結(jié)
這里我們看下std::function的結(jié)構(gòu)信息,如下:
從這里我們發(fā)現(xiàn)_Storage大小為:
constint_Num_ptrs=6+16/sizeof(void*); constsize_t_Space_size=(_Num_ptrs-1)*sizeof(void*);
_Num_ptrs值為10。
如果我們賦值的對象有成員變量會是什么情況呢?例如如下:
classCCaller { public: intoperator()(inta,intb,intc,intd) { std::cout<f; f=Caller; f(10,20,30,40); return0; }
內(nèi)存結(jié)構(gòu)如下:
由此我們可以發(fā)現(xiàn)std::function是利用一個_Compressed_pair<_Alloc, _Callable> _Mypair;拷貝了元素的數(shù)據(jù)信息。
主要的初始化過程為:
emplate
其中decay<_Fx>::type定義了_Compressed_pair<_Alloc, _Callable> _Mypair;中_Callable的類型,這個聲明如下(也就是去掉引用和其他屬性信息):
template
至此,我們大致上完成了std::function的原理分析了,希望在后續(xù)的使用中,我們能夠知道std::function在什么情況下可以使用,以及背后完成的事情。
責任編輯:lq
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4346瀏覽量
63023 -
C++
+關(guān)注
關(guān)注
22文章
2114瀏覽量
73890
原文標題:C++ std::function 技術(shù)淺談
文章出處:【微信號:LinuxHub,微信公眾號:Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
Spire.XLS for C++組件說明
![Spire.XLS for <b class='flag-5'>C++</b>組件說明](https://file1.elecfans.com/web3/M00/05/E7/wKgZO2eFwUuAbuoQAAAbn_khf8A091.png)
EE-112:模擬C++中的類實現(xiàn)
![EE-112:模擬<b class='flag-5'>C++</b>中的類<b class='flag-5'>實現(xiàn)</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
AKI跨語言調(diào)用庫神助攻C/C++代碼遷移至HarmonyOS NEXT
ostream在c++中的用法
OpenHarmony標準系統(tǒng)C++公共基礎(chǔ)類庫案例:HelloWorld
![OpenHarmony標準系統(tǒng)<b class='flag-5'>C++</b>公共基礎(chǔ)類庫案例:HelloWorld](https://file.elecfans.com/web2/M00/26/21/pYYBAGG5jjSALfrEAAAwAa9Oig8799.png)
OpenVINO2024 C++推理使用技巧
C++中實現(xiàn)類似instanceof的方法
![<b class='flag-5'>C++</b>中<b class='flag-5'>實現(xiàn)</b>類似instanceof的方法](https://file1.elecfans.com/web2/M00/FE/0C/wKgaomaYe1CAQ31QAAAnf0IkoSU605.png)
C/C++中兩種宏實現(xiàn)方式
鴻蒙OS開發(fā)實例:【Native C++】
![鴻蒙OS開發(fā)實例:【Native <b class='flag-5'>C++</b>】](https://file1.elecfans.com/web2/M00/C8/31/wKgZomYZMTCAaDv3AAY5x13C324319.jpg)
使用 MISRA C++:2023? 避免基于范圍的 for 循環(huán)中的錯誤
![使用 MISRA <b class='flag-5'>C++</b>:2023? 避免基于范圍的 for 循環(huán)中的錯誤](https://file1.elecfans.com/web2/M00/A9/66/wKgZomUl7m-AHJX6AABuJjgxs14678.png)
評論