重复代码需满足逻辑相同、参数可抽象、复用价值高才值得提成函数;仅结构相似(如简单for循环)若无语义共性则不宜抽取。

重复代码长什么样,才值得提成函数
不是所有看着像重复的代码都适合抽函数。比如两段 for (int i = 0; i 循环,如果循环体里做的事逻辑无关(一个算 sum,一个打印 debug),硬凑成一个函数反而增加耦合。真正该提的,是「相同输入 → 相同行为 → 相同副作用(或无副作用)」的代码块。典型信号包括:连续三行以上完全一致、同一段逻辑在两个以上分支里出现、调试时改一处得同步改多处。
提取时怎么选参数和返回值
别直接把原地变量全塞进参数列表。先问:哪些值每次调用都变?哪些是固定配置?哪些其实是中间结果不该暴露?
- 把会变的、调用方能控制的,设为参数(如
std::string、int threshold) - 把只读的、全局不变的,考虑用
const引用传参或作为静态 constexpr 成员(避免拷贝) - 返回值优先用值语义(
std::vector<int></int>),除非明确需要修改原对象——这时用&或&&,但必须在函数名或注释里说清副作用 - 别为了“看起来整洁”返回
void却靠修改入参输出结果,除非这是公认模式(如std::sort)
命名和作用域容易踩的坑
函数名不是 process_data 或 helper —— 它得说清“做什么”和“对谁做”。比如把一段解析 CSV 行的代码提出来,叫 parse_csv_row 比 handle_line 明确得多。作用域上:
- 只在单个 .cpp 里用的,加
static或放进匿名 namespace,防止链接冲突 - 要跨文件用的,声明放头文件,定义放 .cpp,别头文件里写 inline(除非真需要内联且函数极小)
- 如果函数依赖某个类的私有成员,别硬提成全局函数——这时该考虑把它变成该类的成员函数,哪怕暂时是
private
编译器会不会优化掉你提的函数
现代编译器(GCC/Clang/MSVC 在 -O2 以上)对短小、无副作用的函数大概率自动内联,不用手动加 inline。但要注意:
- 含虚函数调用、
std::mutex、new/delete的函数,基本不会被内联 - 递归函数、函数指针调用点、模板实例化爆炸的场景,内联可能被禁用
- 真正影响性能的是逻辑冗余,不是函数调用开销。与其纠结是否内联,不如确认提取后有没有意外增加拷贝(比如传
std::string而非const std::string&)
复杂点往往不在语法,而在判断哪段“重复”背后其实隐含不同语义——比如两次“打开文件”,一次是读配置,一次是追加日志,强行合并会导致错误抽象。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











