【導(dǎo)讀】:本文主要講解 C++ function 技術(shù)的實(shí)現(xiàn)與具體運(yùn)用。
std::function是一個(gè)函數(shù)對(duì)象的包裝器,std::function的實(shí)例可以存儲(chǔ),復(fù)制和調(diào)用任何可調(diào)用的目標(biāo),包括:
函數(shù)。
lamada表達(dá)式。
綁定表達(dá)式或其他函數(shù)對(duì)象。
指向成員函數(shù)和指向數(shù)據(jù)成員的指針。
當(dāng)std::function對(duì)象沒有初始化任何實(shí)際的可調(diào)用元素,調(diào)用std::function對(duì)象將拋出std::bad_function_call異常。
本文我們來談一下std::function的實(shí)現(xiàn)原理。
1. std::function簡(jiǎn)介
在討論其原理的時(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ù)對(duì)象只有一個(gè)參數(shù),那么這個(gè)代表參數(shù)類型。 |
first_argument_type | 如果函數(shù)對(duì)象有兩個(gè)個(gè)參數(shù),那么這個(gè)代表第一個(gè)參數(shù)類型。 |
second_argument_type | 如果函數(shù)對(duì)象有兩個(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對(duì)象賦值 |
operator bool | 檢查定義的function對(duì)象是否包含一個(gè)有效的對(duì)象 |
operator() | 調(diào)用一個(gè)對(duì)象 |
成員函數(shù)聲明 | 說明 |
---|
1.3 基本使用
#include
從上面我們可以發(fā)現(xiàn),std::function可以表示函數(shù),lamada,可調(diào)用類對(duì)象。
2. std::function實(shí)現(xiàn)
在標(biāo)準(zhǔn)庫中STL設(shè)計(jì)為如下:
template
上面的std::function繼承關(guān)系比較簡(jiǎ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è)來存儲(chǔ)我們?cè)O(shè)置的可調(diào)用對(duì)象,我們從std::function的使用過程看一下整個(gè)原理。
2.1 函數(shù)對(duì)象賦值
我們使用的時(shí)候一般使用f = Caller;來設(shè)置函數(shù)對(duì)象,我們看下這個(gè)的實(shí)現(xiàn)過程。
template
我們看this->_Reset(_Func)這個(gè)函數(shù),因?yàn)檫@個(gè)才是設(shè)置函數(shù)可調(diào)用對(duì)象的東西。
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ù)對(duì)象的調(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。
如果我們賦值的對(duì)象有成員變量會(huì)是什么情況呢?例如如下:
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文章
4306瀏覽量
62431 -
C++
+關(guān)注
關(guān)注
22文章
2104瀏覽量
73496
原文標(biāo)題:C++ std::function 技術(shù)淺談
文章出處:【微信號(hào):LinuxHub,微信公眾號(hào):Linux愛好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論