【導(dǎo)讀】:本文主要講解C++ function技術(shù)的實(shí)現(xiàn)與具體運(yùn)用。
std::function是一個(gè)函數(shù)對象的包裝器,std::function的實(shí)例可以存儲,復(fù)制和調(diào)用任何可調(diào)用的目標(biāo),包括:
函數(shù)。
lamada表達(dá)式。
綁定表達(dá)式或其他函數(shù)對象。
指向成員函數(shù)和指向數(shù)據(jù)成員的指針。
當(dāng)std::function對象沒有初始化任何實(shí)際的可調(diào)用元素,調(diào)用std::function對象將拋出std::bad_function_call異常。
本文我們來談一下std::function的實(shí)現(xiàn)原理。
1. std::function簡介
在討論其原理的時(shí)候,我們來熟悉一下這個(gè)東西是怎么使用的,C++標(biāo)準(zhǔn)庫詳細(xì)說明了這個(gè)的基本使用http://www.cplusplus.com/reference/functional/function/.
這里我們大概總結(jié)一下。
1.1 Member types
result_type | 返回類型 |
argument_type | 如果函數(shù)對象只有一個(gè)參數(shù),那么這個(gè)代表參數(shù)類型。 |
first_argument_type | 如果函數(shù)對象有兩個(gè)個(gè)參數(shù),那么這個(gè)代表第一個(gè)參數(shù)類型。 |
second_argument_type | 如果函數(shù)對象有兩個(gè)個(gè)參數(shù),那么這個(gè)代表第二個(gè)參數(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對象是否包含一個(gè)有效的對象 |
operator() | 調(diào)用一個(gè)對象 |
成員函數(shù)聲明 | 說明 |
---|
1.3 基本使用
#include
從上面我們可以發(fā)現(xiàn),std::function可以表示函數(shù),lamada,可調(diào)用類對象。
2. std::function實(shí)現(xiàn)
在標(biāo)準(zhǔn)庫中STL設(shè)計(jì)為如下:
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 };
這個(gè)來存儲我們設(shè)置的可調(diào)用對象,我們從std::function的使用過程看一下整個(gè)原理。
2.1 函數(shù)對象賦值
我們使用的時(shí)候一般使用f = Caller;來設(shè)置函數(shù)對象,我們看下這個(gè)的實(shí)現(xiàn)過程。
template
我們看this->_Reset(_Func)這個(gè)函數(shù),因?yàn)檫@個(gè)才是設(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
這個(gè)代碼的主要意思就是創(chuàng)建一個(gè)_Func_impl<_Decayed, _Alloc, _Ret, _Types...>指針,然后賦值_Mystorage._Ptrs[_Num_ptrs - 1] = _Ptr;。
設(shè)置之后,我們看下調(diào)用操作怎么完成。
2.2 operator() 的實(shí)現(xiàn)
調(diào)用操作主要是通過operator()來實(shí)現(xiàn)的,我們看下這個(gè)的實(shí)現(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的實(shí)現(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這個(gè)類通過_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是利用一個(gè)_Compressed_pair<_Alloc, _Callable> _Mypair;拷貝了元素的數(shù)據(jù)信息。
主要的初始化過程為:
emplate
其中decay<_Fx>::type定義了_Compressed_pair<_Alloc, _Callable> _Mypair;中_Callable的類型,這個(gè)聲明如下(也就是去掉引用和其他屬性信息):
template
至此,我們大致上完成了std::function的原理分析了,希望在后續(xù)的使用中,我們能夠知道std::function在什么情況下可以使用,以及背后完成的事情。
責(zé)任編輯:lq
-
函數(shù)
+關(guān)注
關(guān)注
3文章
4346瀏覽量
63006 -
C++
+關(guān)注
關(guān)注
22文章
2114瀏覽量
73883 -
初始化
+關(guān)注
關(guān)注
0文章
50瀏覽量
11954
原文標(biāo)題: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++中的類實(shí)現(xiàn)
![EE-112:模擬<b class='flag-5'>C++</b>中的類<b class='flag-5'>實(shí)現(xiàn)</b>](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
AKI跨語言調(diào)用庫神助攻C/C++代碼遷移至HarmonyOS NEXT
運(yùn)動控制卡周期上報(bào)實(shí)時(shí)數(shù)據(jù)IO狀態(tài)之C++篇
![運(yùn)動控制卡周期上報(bào)實(shí)時(shí)數(shù)據(jù)IO狀態(tài)之<b class='flag-5'>C++</b>篇](https://file1.elecfans.com/web3/M00/02/A2/wKgZO2dhD7aAExSYAAKMzmoxqe0256.png)
C7000 C/C++優(yōu)化指南用戶手冊
![<b class='flag-5'>C</b>7000 <b class='flag-5'>C</b>/<b class='flag-5'>C++</b>優(yōu)化指南用戶手冊](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
C7000優(yōu)化C/C++編譯器
![<b class='flag-5'>C</b>7000優(yōu)化<b class='flag-5'>C</b>/<b class='flag-5'>C++</b>編譯器](https://file.elecfans.com/web1/M00/D9/4E/pIYBAF_1ac2Ac0EEAABDkS1IP1s689.png)
ostream在c++中的用法
OpenVINO2024 C++推理使用技巧
C++中實(shí)現(xiàn)類似instanceof的方法
![<b class='flag-5'>C++</b>中<b class='flag-5'>實(shí)現(xiàn)</b>類似instanceof的方法](https://file1.elecfans.com/web2/M00/FE/0C/wKgaomaYe1CAQ31QAAAnf0IkoSU605.png)
C/C++中兩種宏實(shí)現(xiàn)方式
鴻蒙OS開發(fā)實(shí)例:【Native C++】
![鴻蒙OS開發(fā)實(shí)例:【Native <b class='flag-5'>C++</b>】](https://file1.elecfans.com/web2/M00/C8/31/wKgZomYZMTCAaDv3AAY5x13C324319.jpg)
使用 MISRA C++:2023? 避免基于范圍的 for 循環(huán)中的錯(cuò)誤
![使用 MISRA <b class='flag-5'>C++</b>:2023? 避免基于范圍的 for 循環(huán)中的錯(cuò)誤](https://file1.elecfans.com/web2/M00/A9/66/wKgZomUl7m-AHJX6AABuJjgxs14678.png)
評論