std function 的效能陷進

2021-09-26 10:54:35 字數 2576 閱讀 5075

std::function 的作用很強大,他讓vector等儲存不同型別函式的物件: function, functor, lambda…成為了可能。但他有乙個潛在的效能風險:在儲存lambda/bind時,如果物件的大小 大於兩個指標的大小,他就需要分配動態空間。這是大部分人寫c++的人不期望看到的。

先看function實現的幾段**:6.1.0a-2/include/c++/6.1.0/functional

void*       _m_access()       

const void* _m_access() const

template_tp&

_m_access()

1651         _m_init_functor(_any_data& __functor, _functor&& __f, true_type)

1652

1653

1654 static void

1655 _m_init_functor(_any_data& __functor, _functor&& __f, false_type)

1656

1625         static void

1626 _m_init_functor(_any_data& __functor, _functor&& __f)

1627

呼叫哪個函式由_local_storage決定.

1538   class _function_base

1539 ;

咋一看,這個union的大小應該是乙個指標的大小,裡面有個關鍵成員:void (_undefined_class:?_m_member_pointer)(); 指向成員函式的指標,指向成員函式的指標的大小是2個指標的大小。所以結果就是:如果傳入functor的大小大於兩個指標的大小,就會分配動態記憶體。函式指標的大小就是乙個指標的大小,那什麼時候functor會大於乙個指標的大小:lambda和bind。我們以lambda為例來看。bind和lambda的效果一樣。

編譯器在碰到lambda函式時,事實上,會生成乙個物件來儲存lambda函式。這個物件過載了operator(),所以能像函式一樣呼叫。同時,這個物件還有資料成員,這些資料成員就是捕獲來的物件。譬如:

auto lf = [&a, &b];

std::cout << sizeof(lf) << std::endl;

``這個物件捕獲了兩個引用(相當於兩個指標的大小),所以輸出就是16.

# 類成員函式的指標的大小

前面提到類成員函式的指標大小是兩個指標的大小。為什麼? 因為類成員函式的指標還有乙個偏移量, 這個類相對於基類指標的偏移 。

考慮三個類:

```c++

#include #include class a

private:

int a;

};class b

private:

int a;

};class derived: public a, public b ;

我們用derived的物件去訪問函式geta期望返回的是class a的a, 如果訪問getb期望返回的是class b的a;

derived d;

std::cout << "geta: " << d.geta() << ", getb: " << d.getb() << std::endl;

輸出是:

b address: 0x7ffe00762494

a address: 0x7ffe00762490

geta: 1, getb: 2

訪問b的時候,this指標做了偏移,指向了class b在class d中的開始位址。假如使用成員函式指標,這個偏移量,只有在成員函式指標被賦值的時候才能知道。

考慮函式:

void print(derived & d,  int (derived::*p_mem)())

print(d, &derived::geta);

print(d, &derived::getb);

的輸出就是:

a address: 0x7ffc8164e770

print --------

object ptr: 0x7ffc8164e770

function ptr: 0x400b82

point adj: 0

value: 1

b address: 0x7ffc8164e774

print --------

object ptr: 0x7ffc8164e770

function ptr: 0x400bc4

point adj: 0x4

value: 2

參考文章:

如果用std::function的變數來儲存lambda或bind的函式物件時,需要格外注意,如果物件的大小大於兩個指標的大小,就會發生動態記憶體分配,影響效能。

jquery mobile AJAX特性的陷阱

簡單情況是 mvc 重定向,url不變 試了n種方式,跳來跳去,無解,服務端跳,寫js跳,生成跳轉中間頁跳。失敗 後來一看,明明已經跳到新頁了,樣式什麼還是原頁的,有點火大了。出去溜一圈,喝杯水,和同事東拉西扯一通。回頭一看,突然反應過來,這不是ajax的效果麼,坑我半個多小時。為加驗證,是手動呼叫...

std function的本質和使用特性

1.仿函式 又叫std function,是c 中的乙個模板類 2.c語言中的函式指標 int add int a,int b typedef int func int,int 給函式型別定義別名 func func1 func1 add 給函式指標初始化 或者int func1 int,int a...

concat 和 group concat的陷阱

group concat mysql中group concat函式能將相同的行組合起來 完整的語法如下 group concat distinct 要連線的字段 order by asc desc 排序字段 separator 分隔符 使用示例 select from aa id name 1 10...