維尼的蜂巢

RealTime??!! It’s amazing!!!!

C++ 仿函数(functor) 六月 4, 2009

Filed under: VC++/C++/C — kevinlin @ 5:07 下午

仿函數跟callback函數很類似,但是有本質上的不太一樣

仿函數似乎就是把Struct或Class假裝成一個函式的樣子。

舉個例,有這樣的一個struct
struct test
{
       int a;
       int b;
}

有個sort排列要求按a的大小來排,就是
struct sortfunction
{
bool operator()( const test &ta, const test &tb )
{return ta.a < tb.a; }
}

接著就能這樣使用了
std::vector<test > v;
std:: sort( v.begin(), v.end(), sortfunction() )

為什麼不把sortfunction直接寫成一個Function就好,也是可以,但是以類或者結構來處理可以得到更多彈性。

仿函數(functor)的優點

如果可以用仿函數實現,那麼你應該用仿函數,而不要用CallBack。原因在於:

  • 仿函數可以不帶痕跡地傳遞上下文參數。而CallBack技術通常使用一個額外的void*參數傳遞。這也是多數人認為CallBack技術醜陋的原因。
  • 更好的性能。

仿函數技術可以獲得更好的性能,這點直觀來講比較難以理解。你可能說,CallBack函數都寫成inline了,怎麼會性能比仿函數差?我們這裡來分析下。我們假設某個函數func(例如上面的std::sort)調用中傳遞了一個CallBack函數,那麼可以分為兩種情況:

  • func是inline函數,並且比較簡單,func呼叫最後被展開了,那麼其中對CallBack函數的呼叫也成為一普通函數呼叫(而不是通過函數指標的間接呼叫),並且如果這個CallBack函數很簡單,那麼也可能同時被展開。在這種情形下,CallBack函數與仿函數性能相同。
  • func是非inline函數的話,或者比較複雜而無法展開(例如上面的std::sort,我們知道它是快速排序,函數因為存在遞回而無法展開)。此時CallBack函數作為一個函數指標傳入,他的程式碼也是無法被展開。而仿函數則不同。雖然func本身複雜不能展開,但是func函數中對仿函數的呼叫是編譯器編譯期間就可以確定並進行inline展開的。因此在這種情形下,仿函數比之於CallBack函數,有著更好的性能。並且,這種性能優勢有時是一種無可比擬的優勢(對於std::sort就是如此,因為元素比較的次數非常巨大,是否可以進行inline展開導致了一種雪崩效應)。

仿函數(functor)不能做的?

話又說回來了,仿函數並不能完全取代CallBack函數所有的應用場合。例如,我在std::AutoFreeAlloc中使用了CallBack函數,而不是仿函數,這是因為AutoFreeAlloc要容納異質的解構函數,而不是只支持某一種類的解構。這和模板(template)不能在同一個容器中支持異質類型,是一樣的。

 

5 Responses to “C++ 仿函数(functor)”

  1. Allen Says:

    你好!在找資料途中,發現你這篇有趣的文章,請問能否將它引用至我的部落格呢?懇請回答,謝謝。

  2. […] C++ 仿函数(Functor) 大意是講說 functor 把class或structure 當成一般函數來處理,所以才可以有這種特殊的寫法。 這篇文章中,也對於Functor的優缺點做了精闢的分析,有興趣的讀者可以前往觀看。 另外,再補上國外一個關於Functor的教學: http://www.newty.de/fpt/functor.html Categories: 程式設計 標籤:程式設計 迴響 (0) 引用 (0) 發表迴響 引用通告 […]

  3. yagami Says:

    您好,我想引用您的文章裡面的敘述到我的blog上,請問是否可以呢?謝謝~:)


發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 變更 )

Twitter picture

You are commenting using your Twitter account. Log Out / 變更 )

Facebook照片

You are commenting using your Facebook account. Log Out / 變更 )

Google+ photo

You are commenting using your Google+ account. Log Out / 變更 )

連結到 %s