c++复习自存--理解函数对象、lambda表达式、STL算法

📅 2026/7/9 12:44:04
c++复习自存--理解函数对象、lambda表达式、STL算法
理解函数对象一、函数对象与谓词的概念1. 函数对象仿函数重载了operator()的类/结构体实例称为函数对象语法上可以像普通函数一样直接调用。核心优势可携带状态类内部可以定义成员变量保存调用过程中的临时数据普通全局函数无法做到兼容STL算法可以作为参数传入sort、find_if等标准算法编译期优化类内重载运算符可被编译器内联展开运行效率高于函数指针。基础示例// 函数对象类classAdd{public:intbase;Add(intb):base(b){}// 重载()运算符intoperator()(intx)const{returnbasex;}};intmain(){Addadd5(5);intresadd5(3);// 等价调用operator()结果8return0;}2. 谓词特殊的函数对象返回值为bool类型专门用于STL算法做条件判断、大小比较。分类标准根据operator()接收参数个数分为一元谓词、二元谓词。二、函数对象的典型用途1. 一元函数仅接收一个参数的函数对象无返回值限制常用于单元素处理逻辑。示例批量数值自增处理#includevector#includealgorithm#includeiostreamstructInc{intstep;Inc(ints):step(s){}voidoperator()(intnum){numstep;}};intmain(){vectorintvec{1,2,3,4};// for_each遍历传入一元函数对象for_each(vec.begin(),vec.end(),Inc(2));return0;}2. 一元谓词接收单个参数、返回bool的函数对象多用于find_if、remove_if等筛选类算法判断单个元素是否满足条件。示例筛选大于10的数字structGreaterTen{booloperator()(intx)const{returnx10;}};intmain(){vectorintvec{5,12,8,15};autoitfind_if(vec.begin(),vec.end(),GreaterTen());if(it!vec.end())cout找到第一个大于10的数*it;return0;}3. 二元函数接收两个参数的函数对象无返回值类型限制用于双元素运算逻辑。示例两数相乘运算structMultiply{intoperator()(inta,intb)const{returna*b;}};4. 二元谓词接收两个参数、返回bool的函数对象核心用于sort自定义排序、set/map自定义比较规则判断两个元素的大小关系。示例sort降序排序二元谓词structDescSort{booloperator()(inta,intb)const{returnab;}};intmain(){vectorintvec{3,1,4,2};sort(vec.begin(),vec.end(),DescSort());return0;}补充拓展与lambda的关系C11之后lambda表达式本质是匿名函数对象底层编译器自动生成重载operator()的隐藏类标准库内置谓词STL提供greaterT、lessT、not_equal_toT等现成二元谓词not1、not2用于取反一元/二元谓词状态存储对比普通函数指针无法保存中间变量函数对象依靠成员变量实现带状态回调是STL算法自定义逻辑的核心载体。lambda表达式一、lambda表达式是什么lambda是C11引入的匿名函数对象编译器底层会自动生成一个重载operator()的隐藏类无需手动定义仿函数结构体可直接在代码行内临时创建一段可执行逻辑。核心优势就地定义不用单独写全局/类内函数简化STL算法传参通过捕获列表直接访问当前作用域局部变量天然携带运行状态可兼容一元/二元函数、谓词完全替代传统手写函数对象。二、如何定义lambda表达式最简基础结构[捕获列表](参数列表){函数体};#includeiostreamusingnamespacestd;intmain(){// 无捕获、无参数lambdaautohello[](){coutHello Lambdaendl;};hello();// 调用匿名函数return0;}auto关键字用于自动推导lambda的独特函数对象类型lambda无法直接显式声明类型必须用auto接收。三、一元函数对应的lambda表达式仅接收单个形参无返回值限制对应上一章的一元函数对象常搭配for_each遍历容器。#includevector#includealgorithmintmain(){vectorintvec{1,2,3,4};// 一元lambda单个参数x实现数值5for_each(vec.begin(),vec.end(),[](intx){x5;});return0;}四、一元谓词对应的lambda表达式接收单个参数返回bool布尔值等价一元谓词多用于find_if、remove_if筛选容器元素。#includevector#includealgorithmintmain(){vectorintvec{2,15,7,20};// 一元谓词lambda判断元素是否大于10autoitfind_if(vec.begin(),vec.end(),[](intx){returnx10;});if(it!vec.end())cout第一个大于10的元素*it;return0;}五、通过捕获列表接受状态变量的lambda表达式捕获列表[]作用读取/修改lambda外部作用域的局部变量提供多种捕获规则[]值捕获拷贝外部所有变量lambda内只读无法修改原变量[]引用捕获绑定外部所有变量引用可直接修改原变量[var]单独值捕获仅拷贝指定变量[var]单独引用捕获仅绑定指定变量引用[this]捕获当前类成员指针访问类内成员。示例带状态捕获intmain(){intlimit10;vectorintvec{3,12,9,18};// [] 值捕获limit读取外部变量作为判断条件autoitfind_if(vec.begin(),vec.end(),[](intx){returnxlimit;});// [] 引用捕获可修改外部countintcount0;for_each(vec.begin(),vec.end(),[](intx){if(xlimit)count;});return0;}若需要值捕获同时修改内部副本可添加mutable关键字intnum5;autofunc[]()mutable{num2;coutnum;};六、lambda表达式的通用语法完整标准语法[捕获列表](形参列表)mutable-返回类型{函数体};各分段说明[]捕获列表必填控制外部变量访问规则(参数)形参列表可选无参数可省略括号C14起mutable修饰符可选值捕获时允许修改拷贝后的变量副本- 返回类型尾置返回可选函数体内有多条分支返回不同类型时必须显式声明单返回值编译器可自动推导可省略{}函数体必填存放业务逻辑。完整显式返回值示例autoadd[](inta,intb)-int{returnab;};七、二元函数对应的lambda表达式接收两个形参对应二元函数对象多用于双元素运算、容器并行遍历。// 二元lambda接收a、b两个参数返回乘积automul[](inta,intb){returna*b;};intresmul(6,7);八、二元谓词对应的lambda表达式接收两个参数返回bool等价二元谓词最常用在sort自定义排序逻辑、有序容器比较规则。#includevector#includealgorithmintmain(){vectorintvec{5,1,9,3};// 二元谓词lambda实现降序排序sort(vec.begin(),vec.end(),[](inta,intb){returnab;});return0;}lambda与传统函数对象对比简洁性lambda就地定义无需单独编写struct/类代码紧凑状态捕获捕获列表自动处理外部变量不用手动在构造函数传参保存状态通用性一元/二元函数、谓词场景全部兼容覆盖STL算法所有自定义回调需求限制lambda为匿名类型无法作为类成员存储可借助std::function包装。STL算法一、什么是STL算法STL算法是标准库提供的通用处理函数集合头文件为algorithm核心设计思想与容器解耦全部基于迭代器实现不依赖容器底层结构一套算法可作用于vector、list、string等所有支持迭代器的容器支持自定义逻辑注入可传入函数指针、仿函数、lambda表达式作为判断/处理规则分为只读、修改、排序、查找等多类功能覆盖绝大多数容器遍历、筛选、变换需求替代手写循环简化代码。二、STL算法的分类1. 非变序算法仅读取区间元素不会修改容器内原始数据、不会改变元素存储顺序属于只读类算法。代表接口find、count、for_each、equal、search。适用场景查找元素、统计数量、遍历读取、对比序列内容。2. 变序算法会修改区间内元素的值或调整元素存储位置、移动元素改变原有序列状态。细分原地修改fill、generate、transform、replace移动/重排copy、remove、sort、partition、unique。三、使用STL算法1. 根据值或条件查找元素用于在区间中定位目标元素返回匹配元素的迭代器无匹配返回end()。find(begin, end, val)按固定值正向查找find_if(begin, end, 一元谓词)按自定义条件查找find_if_not查找第一个不满足条件的元素。vectorintvec{2,5,9,4};// 查找值为9的元素autoit1find(vec.begin(),vec.end(),9);// lambda条件查找大于6的第一个元素autoit2find_if(vec.begin(),vec.end(),[](intx){returnx6;});2. 计算包含给定值或满足给定条件的元素数统计区间内匹配元素总个数返回数值size_tcount(begin, end, val)统计等于目标值的元素count_if(begin, end, 一元谓词)统计满足自定义条件的元素。vectorintvec{1,2,2,3,2};intnum1count(vec.begin(),vec.end(),2);// 结果3intnum2count_if(vec.begin(),vec.end(),[](intx){returnx%20;});3. 在集合中搜索元素或序列用于查找子序列、区间匹配多用于有序/无序序列批量匹配search查找完整子序列首次出现位置search_n查找连续n个相同元素adjacent_find查找相邻重复元素。vectorintsrc{1,3,5,7,3,5};vectorintsub{3,5};autoitsearch(src.begin(),src.end(),sub.begin(),sub.end());4. 将容器中的元素初始化为指定值批量填充区间固定数值原地覆盖原有内容fill(begin, end, val)全区间填充单一值fill_n(start, n, val)从起始位置填充n个元素。vectorintvec(10);fill(vec.begin(),vec.end(),0);// 全部置0fill_n(vec.begin(),5,100);// 前5个元素设为1005. 使用std::generate()将元素设置为运行阶段生成的值和fill的区别填充值由生成函数动态实时计算而非固定常量。generate(begin, end, 生成函数)填充整个区间generate_n(start, n, 生成函数)填充指定个数元素。intnum1;// 每次调用lambda自增生成1,2,3...generate(vec.begin(),vec.end(),[](){returnnum;});6. 使用for_each()处理指定范围内的元素遍历区间每一个元素执行自定义逻辑无返回值等价手写for循环vectorintvec{1,2,3};// 遍历打印所有元素for_each(vec.begin(),vec.end(),[](intx){coutx ;});// 遍历修改元素for_each(vec.begin(),vec.end(),[](intx){x*2;});7. 使用std::transform()对范围进行变换读取原区间元素通过转换函数生成新值支持原地修改或输出到另一容器分为一元、二元变换一元transform单输入区间二元transform两个输入区间同步运算。vectorintsrc{1,2,3},dst;dst.resize(src.size());// 每个元素平方后存入dsttransform(src.begin(),src.end(),dst.begin(),[](intx){returnx*x;});8. 复制和删除操作复制系列copy将源区间元素复制到目标容器copy_if仅复制满足条件的元素copy_backward反向复制避免覆盖冲突。删除系列逻辑删除remove(val)、remove_if(条件)仅将匹配元素移至区间尾部返回新有效区间尾迭代器需配合容器erase真正释放空间vectorintvec{1,5,2,5,3};// 移除所有值为5的元素autonew_endremove(vec.begin(),vec.end(),5);vec.erase(new_end,vec.end());9. 替换值以及替换满足给定条件的元素原地修改区间匹配元素的值replace(begin, end, old_val, new_val)固定值替换replace_if(begin, end, 谓词, new_val)条件匹配后替换。vectorintvec{2,7,2,9};replace(vec.begin(),vec.end(),2,0);// 将大于5的数字统一替换为10replace_if(vec.begin(),vec.end(),[](intx){returnx5;},10);10. 排序、在有序集合中搜索以及删除重复元素排序sort快速排序默认升序可传入二元谓词自定义排序规则stable_sort稳定排序保留相等元素原始相对位置。有序查找仅适用于已排序区间binary_search二分查找、lower_bound/upper_bound边界迭代器。去重unique将连续重复元素移至尾部返回有效区间终点搭配erase彻底删除重复值使用前必须先排序vectorintvec{2,1,2,1,3};sort(vec.begin(),vec.end());autolastunique(vec.begin(),vec.end());vec.erase(last,vec.end());11. 将范围分区partition根据条件把区间分为两部分满足条件的放前半段不满足放后半段返回分割点迭代器stable_partition稳定分区保留组内原有相对顺序。vectorintvec{1,6,3,8,2};// 偶数放前面奇数放后面automidpartition(vec.begin(),vec.end(),[](intx){returnx%20;});12. 在有序集合中插入元素针对已升序排序的区间找到插入位置并插入维持整体有序lower_bound找到第一个大于等于目标值的位置配合容器insert完成有序插入vectorintvec{1,3,5,7};intval4;autoposlower_bound(vec.begin(),vec.end(),val);vec.insert(pos,val);补充拓展迭代器约束不同算法对迭代器能力有要求sort需要随机访问迭代器因此std::list不能使用全局sort只能调用自身成员sort性能区分二分查找类算法仅适用于有序区间复杂度O(logN)远快于线性查找find容器专属算法list、forward_list提供专属sort、unique底层适配链表结构比全局算法效率更高。