mem_fun_t/ptr_fun等用法

本文详细解析了STL中预定义的函数对象及其适配器,包括mem_fun_t、mem_fun_ref、ptr_fun等的使用场景与区别,以及如何通过这些工具灵活地在容器中应用成员函数。

 

1、mem_fun_t

1-用于遍历调用多态的虚函数,容器元素是指针  

2-const_mem_fun:用于const的成员函数,用法类似

std::vector<B*> V;

V.push_back(new D1);

V.push_back(new D2);

V.push_back(new D2);

V.push_back(new D1); 

std::for_each(V.begin(), V.end(),std::mem_fun(&B::print));

2、mem_fun_ref

用于遍历调用多态的虚函数,容器元素是引用

const_mem_fun_ref:用于const的成员函数,用法类似 

std::vector<D1> V;

V.push_back(D1());

V.push_back(D1()); 

std::for_each(V.begin(), V.end(),std::mem_fun_ref(&B::print));

3、pointer_to_unary_function/pointer_to_binary_function

//pointer_to_unary_function<Arg, Result>,用于把一个参数的C函数转为函数对象,

//pointer_to_binary_function<Arg1, Arg2, Result>,同上,把两个参数的C函数转为函数对象

注意:

如果没有compose1,可以直接使用C函数如fabs,则不需要std::ptr_fun()的辅助 

std::transform(V1.begin(), V1.end(), V1.begin(), fabs);   //直接使用fabs时不需要使用ptr_fun

std::transform(V1.begin(), V1.end(), V1.begin(),  compose1(std::negate<double>(),  std::ptr_fun(fabs))); 

4、mem_fun和mem_fun_ref的区别?

mem_fun_ref的作用和用法跟mem_fun一样,

唯一的不同就是:当容器中存放的是对象实体的时候用mem_fun_ref,当容器中存放的是对象的指针的时候用mem_fun

class ClxECS
{
public:
    int DoSomething() 
    { 
        // 这里以输出一句话来代替具体的操作
        cout << "Output frommethod DoSomething!" << endl; 
        return 0; 
    };
};

vector<ClxECS*> vECS;

for_each(vECS.begin(), vECS.end(), mem_fun(&ClxECS::DoSomething));        

例子:

list<Widget *> lpw;
for_each(lpw.begin(), lpw.end(),mem_fun(&Widget::test)); // pw->test();

vector<Widget> vw;
for_each(vw.begin(), vw.end(),mem_fun_ref(&Widget::test)); // w.test();

成员函数有参数的情况:将值传入,再bind1st为this

std::for_each(m_erased.begin(), m_erased.end(),

                     std::bind1st(std::mem_fun(&SocketSet::_replace_with_last), this));
//相当于this->_replace_with_last(iter) //iter

5、ptr_fun

ptr_fun是将一个普通的函数适配成一个仿函数(functor), 添加上argument_type和result type等类型,它的定义如下:
template<class _Arg1,
    class _Arg2,
    class _Result> inline
    pointer_to_binary_function<_Arg1, _Arg2, _Result,
        _Result(__clrcall *)(_Arg1, _Arg2)>
            ptr_fun(_Result (__clrcall *_Left)(_Arg1, _Arg2))
    {    // return pointer_to_binary_function functor adapter
    return (pointer_to_binary_function<_Arg1, _Arg2, _Result,
        _Result (__clrcall *)(_Arg1, _Arg2)>(_Left));
    }
下面的例子就是说明了使用ptr_fun将普通函数(两个参数, 如果有多个参数, 要改用boost::bind)适配成bind1st或bind2nd能够使用的functor,否则对bind1st或bind2nd直接绑定普通函数,则编译出错。
#include <algorithm>  
#include <functional>  
#include <iostream>  
using namespace std;  
 
int sum(int arg1, int arg2)  
{  
    std::cout<< "arg1 = " << arg1 << std::endl;  
    std::cout<< "arg2 = " << arg2 << std::endl;  
 
    int sum = arg1 + arg2;  
    std::cout << "sum = " << sum << std::endl;  
    return sum;  
}
 
int main(int argc, char *argv[], char *env[])
{  
    bind1st(ptr_fun(sum), 1)(2);        // the same as sum(1,2)  
    bind2nd(ptr_fun(sum), 1)(2);        // the same as sum(2,1)  
    return 0;

}

6、总结篇:

………………………………………………………………………………………………………………………………

STL中包含许多预定义的函数对象,其中有:

算术操作:plus, minus, multiplies, divides, modulus, 和negate,例:
assert(V2.size() >= V1.size() && V3.size() >= V1.size());
transform(V1.begin(), V1.end(), V2.begin(), V3.begin(),modulus<int>());

把V1[i]%V2[i]存入V3[i]。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

比较操作:equal_to, not_equal_to, greater, less, greater_equal, 和 less_equal,例:
list<int>::iterator first_nonnegative = find_if(L.begin(),  L.end(),  bind2nd(greater_equal<int>(), 0));

在L中找到第一个大于等于0的元素。
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

逻辑操作:logical_and, logical_or, 和 logical_not,例:
char str[MAXLEN];
const char* wptr = find_if(str, str + MAXLEN,compose2(logical_or<bool>(),

                                           bind2nd(equal_to<char>(), ' '),

                                           bind2nd(equal_to<char>(),'\n')));
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

修改、组装已有函数对象生成新的函数对象:unary_compose, binary_compose, unary_negate,

 binary_negate,binder1st, binder2nd, pointer_to_unary_function,

pointer_to_binary_function,mem_fun_t, mem_fun_ref_t, mem_fun1_t 和mem_fun1_ref_t。

^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
说明:
函数对象模板类名                          辅助函数名                             说明                                          生成函数对象

unary_compose                                compose1              unary_compose(f,g)                          f(g(x))
binary_compose                              compose2            binary_compose(f,g1,g2)               f(g1(x), g2(x))
unary_negate                                      not1                           unary_negate(pred)                     一元谓词取非
binary_negate                                     not2                      binary_negate(pred)                          二元谓词取非
binder1st                                          bind1st                      binder1st(F,c)                     二元函数对象的第一个参数绑定为c
binder2st                                          bind2st                       binder2st(F,c)                        二元函数对象的第二个参数绑定为c
pointer_to_unary_function
pointer_to_binary_function           ptr_fun                  只能有1个或2个参数

mem_fun_t
mem_fun1_t                                  mem_fun            成员函数(只能有0个或1个参数,

 
区别:

struct T{
     print(){}
};

list<T*>lstT;
for_each(lstT.begin(),lstT.end(),mem_fun(&T::print));

list<T> lstT;
for_each(lstT.begin(),lstT.end(),mem_fun_ref(&T::print));

 

/*----------------------------------------------------------------------- 第13章 Hook技术 《加密与解密(第四版)》 (c) 看雪学院 www.kanxue.com 2000-2018 -----------------------------------------------------------------------*/ // VEHHook.cpp : Defines the entry point for the console application. // #include "stdafx.h" #include <windows.h> BOOL SetBreakPoint(PVOID pFuncAddr); BOOL ClearBreakPoint(PVOID pFuncAddr); BOOL InstallVEHHook(PVECTORED_EXCEPTION_HANDLER Handler); VOID UnInstallVEHHook(); typedef int (WINAPI *PFN_MessageBox)( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box ); int WINAPI My_MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box ); LONG WINAPI VectoredHandler1(struct _EXCEPTION_POINTERS *ExceptionInfo); LONG WINAPI VectoredHandler2(struct _EXCEPTION_POINTERS *ExceptionInfo); LONG WINAPI VectoredHandler3(struct _EXCEPTION_POINTERS *ExceptionInfo); VOID ShowMsgBox(LPCTSTR lpMsg); ULONG_PTR InitTrampolineFun(); PFN_MessageBox g_OriginalMessageBoxA; PVOID g_AddrofMessageBoxA = 0 ; PVOID g_hVector; BYTE g_OldCode[16]={0}; int main(int argc, char* argv[]) { HMODULE hUser32 = LoadLibrary("user32.dll"); g_AddrofMessageBoxA = (PVOID)GetProcAddress(hUser32,"MessageBoxA"); printf("Address of MessageBoxA = 0x%p\n",g_AddrofMessageBoxA); g_OriginalMessageBoxA = (PFN_MessageBox)InitTrampolineFun(); //跳过开头的Hook printf("Addr of VectoredHandler1 = 0x%p\n",VectoredHandler1); printf("Addr of VectoredHandler2 = 0x%p\n",VectoredHandler2); printf("Addr of VectoredHandler3 = 0x%p\n",VectoredHandler3); //选择安装一个进行测试 InstallVEHHook(VectoredHandler1); //设置断点 SetBreakPoint(g_AddrofMessageBoxA); //call ShowMsgBox("VEH Hook Test."); printf("All Finished!\n"); ClearBreakPoint(g_AddrofMessageBoxA); UnInstallVEHHook(); ShowMsgBox("Hook Cleared"); return 0; } VOID ShowMsgBox(LPCTSTR lpMsg) { MessageBoxA(NULL,lpMsg,"Test",MB_OK); } ULONG_PTR InitTrampolineFun() { ULONG_PTR uResult = 0 ; PBYTE pFun = NULL; #ifdef _WIN64 //x64需要申请shellcode /* USER32!MessageBoxA: 00000000`779412b8 4883ec38 sub rsp,38h 00000000`779412bc 4533db xor r11d,r11d 00000000`779412bf 44391d760e0200 cmp dword ptr [USER32!gapfnScSendMessage+0x927c (00000000`7796213c)],r11d */ pFun = (PBYTE)VirtualAlloc(NULL,128,MEM_COMMIT,PAGE_EXECUTE_READWRITE); uResult = (ULONG_PTR)pFun; memset(pFun,0,128); memcpy(pFun,(PVOID)g_AddrofMessageBoxA,4); //拷贝第一条指令,4字节,推荐使用反汇编引擎来实际计算 pFun += 4 ; //下一条指令构造为jmp [xxxxxx] pFun[0] = 0xFF; pFun[1] = 0x25; *(ULONG_PTR*)(pFun + 6) = (ULONG_PTR)g_AddrofMessageBoxA + 4 ; //跳回到原函数加4的地方 #else //x86,第一条指令是mov edi,edi,直接跳过即可 uResult = (ULONG_PTR)g_AddrofMessageBoxA + 2; #endif return uResult; } //处理方式,修改参数并返回原函数继续执行 LONG WINAPI VectoredHandler1( struct _EXCEPTION_POINTERS *ExceptionInfo ) { char *szNewMsg = "[VectoredHandler1] Hacked by pediy.com"; LONG lResult = EXCEPTION_CONTINUE_SEARCH ; PEXCEPTION_RECORD pExceptionRecord; PCONTEXT pContextRecord; int ret = 0 ; pExceptionRecord = ExceptionInfo->ExceptionRecord ; pContextRecord = ExceptionInfo->ContextRecord ; ULONG_PTR* uESP = 0 ; printf("Exception Address = %p\n",pExceptionRecord->ExceptionAddress); if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT && pExceptionRecord->ExceptionAddress == g_AddrofMessageBoxA) { #ifdef _WIN64 //x64上前四个参数依次为RCX,RDX,R8,R9 //修改第二个参数,即LpMsg printf("lpText = 0x%p %s\n",pContextRecord->Rdx,(char*)pContextRecord->Rdx); pContextRecord->Rdx = (ULONG_PTR)szNewMsg; pContextRecord->Rip = (ULONG_PTR)g_OriginalMessageBoxA ; //跳到Trampoline继续执行 #else /* 0012FF70 0040105A /CALL 到 MessageBoxA 来自 VEHHook.00401054 0012FF74 00000000 |hOwner = NULL 0012FF78 00407030 |Text = "VEH Hook" 0012FF7C 0040703C |Title = "Test" 0012FF80 00000000 \Style = MB_OK|MB_APPLMODAL 0012FF84 00401225 返回到 VEHHook.<ModuleEntryPoint>+0B4 来自 VEHHook.00401000 */ printf("ESP = 0x%p\n",pContextRecord->Esp) ; uESP = (ULONG_PTR*)pContextRecord->Esp ; //取中断时的ESP uESP[2] = (ULONG_PTR)szNewMsg; //修改栈中的参数 pContextRecord->Eip = (ULONG_PTR)g_OriginalMessageBoxA ; //跳过函数开头 #endif lResult = EXCEPTION_CONTINUE_EXECUTION ; } return lResult; } //处理方式:直接调用原函数并替原函数返回 LONG WINAPI VectoredHandler2( struct _EXCEPTION_POINTERS *ExceptionInfo ) { char *szNewMsg = "[VectoredHandler2] Hacked by pediy.com"; LONG lResult = EXCEPTION_CONTINUE_SEARCH ; PEXCEPTION_RECORD pExceptionRecord; PCONTEXT pContextRecord; int ret = 0 ; pExceptionRecord = ExceptionInfo->ExceptionRecord ; pContextRecord = ExceptionInfo->ContextRecord ; ULONG_PTR* uESP = 0 ; if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT && pExceptionRecord->ExceptionAddress == g_AddrofMessageBoxA) { #ifdef _WIN64 //x64上前四个参数依次为RCX,RDX,R8,R9 printf("RSP = 0x%p\n",pContextRecord->Rsp) ; uESP = (ULONG_PTR*)pContextRecord->Rsp ; printf("Return Address = 0x%p\n",uESP[0]); ret = g_OriginalMessageBoxA((HWND)pContextRecord->Rcx,szNewMsg,(LPCTSTR)pContextRecord->R8,(int)pContextRecord->R9); printf("ret = %d\n",ret); //修正RSP pContextRecord->Rsp += sizeof(ULONG_PTR);//参数在寄存器中,栈中无参数,仅需跳过返回地址 //直接返回到调用者处 pContextRecord->Rip = uESP[0] ;//设置EIP为返回地址 #else /* 0012FF70 0040105A /CALL 到 MessageBoxA 来自 VEHHook.00401054 0012FF74 00000000 |hOwner = NULL 0012FF78 00407030 |Text = "VEH Hook" 0012FF7C 0040703C |Title = "Test" 0012FF80 00000000 \Style = MB_OK|MB_APPLMODAL 0012FF84 00401225 返回到 VEHHook.<ModuleEntryPoint>+0B4 来自 VEHHook.00401000 */ printf("ESP = 0x%p\n",pContextRecord->Esp) ; uESP = (ULONG_PTR*)pContextRecord->Esp ; ret = g_OriginalMessageBoxA((HWND)uESP[1],szNewMsg,(LPCTSTR)uESP[3],(int)uESP[4]); printf("ret = %d\n",ret); //直接返回到调用者处 pContextRecord->Eip = uESP[0] ;//设置EIP为返回地址 pContextRecord->Esp += (4 + 1)*sizeof(ULONG_PTR); //4为参数个数,1为返回地址 #endif lResult = EXCEPTION_CONTINUE_EXECUTION ; } return lResult; } //处理方式:直接返回,相当于过滤掉 LONG WINAPI VectoredHandler3( struct _EXCEPTION_POINTERS *ExceptionInfo ) { LONG lResult = EXCEPTION_CONTINUE_SEARCH ; PEXCEPTION_RECORD pExceptionRecord = ExceptionInfo->ExceptionRecord ; PCONTEXT pContextRecord = ExceptionInfo->ContextRecord ; ULONG_PTR* uESP = 0 ; if (pExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT && pExceptionRecord->ExceptionAddress == g_AddrofMessageBoxA) { /* 0012FF70 0040105A /CALL 到 MessageBoxA 来自 VEHHook.00401054 0012FF74 00000000 |hOwner = NULL 0012FF78 00407030 |Text = "VEH Hook" 0012FF7C 0040703C |Title = "Test" 0012FF80 00000000 \Style = MB_OK|MB_APPLMODAL 0012FF84 00401225 返回到 VEHHook.<ModuleEntryPoint>+0B4 来自 VEHHook.00401000 */ //直接返回到调用者处 #ifdef _WIN64 printf("RSP = 0x%p\n",pContextRecord->Rsp) ; uESP = (ULONG_PTR*)pContextRecord->Rsp ; pContextRecord->Rip = uESP[0] ;//设置EIP为返回地址 pContextRecord->Rsp += sizeof(ULONG_PTR); //将压入栈内的参数和返回地址清理掉,4为参数个数,1为返回地址 #else printf("ESP = 0x%X\n",pContextRecord->Esp) ; uESP = (ULONG_PTR*)pContextRecord->Esp ; pContextRecord->Eip = uESP[0] ;//设置EIP为返回地址 pContextRecord->Esp += (4 + 1)*sizeof(ULONG_PTR); //将压入栈内的参数和返回地址清理掉,4为参数个数,1为返回地址 #endif lResult = EXCEPTION_CONTINUE_EXECUTION ; } return lResult; } BOOL InstallVEHHook(PVECTORED_EXCEPTION_HANDLER Handler) { printf("Current Handler Address = 0x%p\n",Handler); g_hVector = AddVectoredExceptionHandler(1,Handler); return g_hVector != NULL ; } VOID UnInstallVEHHook() { RemoveVectoredExceptionHandler(g_hVector); } /* 0:000> u user32!messageboxA USER32!MessageBoxA: 77d507ea 8bff mov edi,edi 77d507ec 55 push ebp 77d507ed 8bec mov ebp,esp */ BOOL SetBreakPoint(PVOID pFuncAddr) { DWORD dwCnt = 0 ; BYTE *pTarget = (BYTE*)pFuncAddr; g_OldCode[0] = *pTarget; printf("Original Fun Head Code = 0x%02X\n",g_OldCode[0]); //修改内存页的属性 DWORD dwOLD; MEMORY_BASIC_INFORMATION mbi; VirtualQuery(pTarget,&mbi,sizeof(mbi)); VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&dwOLD); //写入int3 *pTarget = 0xCC ; //恢复内存页的属性 VirtualProtect(mbi.BaseAddress,mbi.RegionSize,dwOLD,0); return TRUE; } BOOL ClearBreakPoint(PVOID pFuncAddr) { BYTE *pTarget = (BYTE*)pFuncAddr; //修改内存页的属性 DWORD dwOLD; MEMORY_BASIC_INFORMATION mbi; VirtualQuery(pTarget,&mbi,sizeof(mbi)); VirtualProtect(mbi.BaseAddress,mbi.RegionSize,PAGE_EXECUTE_READWRITE,&dwOLD); *pTarget = g_OldCode[0] ; //恢复内存页的属性 VirtualProtect(mbi.BaseAddress,mbi.RegionSize,dwOLD,0); return TRUE; } int WINAPI My_MessageBox( HWND hWnd, // handle of owner window LPCTSTR lpText, // address of text in message box LPCTSTR lpCaption, // address of title of message box UINT uType // style of message box ) { char newMsg[400]; char newCation[]="标题被我改了!"; int result; if (lpText) { ZeroMemory(newMsg,400); lstrcpy(newMsg,lpText); lstrcat(newMsg,"\n\tMessage Box hacked by pediy.com"); } printf("有人调用MessageBox...\n"); result = g_OriginalMessageBoxA(hWnd,newMsg,newCation,uType); return result; }分析是什么代码?有什么作用?如何执行
最新发布
07-25
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值