如何安全地从粗糙的C++代码中提取函数
How can I safely extract a function from gnarly C++ code?
假设我有一个5000行长、嵌套很深的函数,我想将一个1000行的块提取到一个新函数中。
在Java和C#中,我可以让ReSharper、IntelliJ和Visual C#处理安全提取方法所需的分析,无论代码有多长和多粗糙。我可以确信,它们不会改变代码的行为,即使它太复杂了,我的小脑袋无法理解。
现有的C++工具无法给我同样的信心。CLion、ReSharper和Visual Assist在提取方法时都会引入行为更改。
我有什么选择?
一种选择是根据Tennent的对应原理使用此配方。您可以将其应用于整个块(用大括号包围)或if
、while
或for
语句(它们创建自己的作用域)。
1.引入lambda并将其称为
用包围有问题的块
[&]() {
// original code
}();
编译文件可能的错误:
并非所有控制路径都返回一个值你很早就回来了。备份并消除提前返回/继续/中断或提取不同的内容。
中断/继续语句只能在…中使用你可以休息/继续。备份并消除提前返回/继续/中断或提取不同的内容。
检查新lambda中是否有任何返回语句如果有任何返回,并且很明显所有代码路径都返回,那么在lambda之后的下一行添加一个return语句。如果有任何返回,并且不明显所有代码路径都返回,则备份并消除早期返回/继续/中断,或者尝试提取不同的内容。
2.在lambda上引入变量
即
[&]() {
// ...
}();
变为:
auto Applesauce = [&]() {
// ...
};
Applesauce();
编译以确保您没有拼写错误。
3.设置退货类型
设置lambda的返回类型(即使它是void
)。在Visual Studio中,auto
上的工具提示将告诉您类型。
即:
auto Applesauce = [&]() -> SOMETYPE {
// ...
};
编译以确保返回类型正确。
4.明确捕获
将[&]
替换为[this]
(或自由函数中的[]
)并编译。
对于必须捕获的变量的每个错误:-复制变量名-将其粘贴到捕获列表中,前缀为&
-重复此步骤,直到绿色。
即:
auto Applesauce = [this, &foo]() -> void {
cout << foo;
};
捕获列表的顺序将影响最终函数的参数的顺序。如果您希望参数按特定顺序排列,现在是重新排序捕获列表的好时机。
5.将捕获转换为参数
对于每个捕获的局部变量(this
除外)-转到变量的定义-复制变量声明(例如Column* pCol
)-粘贴到lambda参数列表-通过引用使参数常量和-从捕获列表中删除变量-将变量传入调用-编译。
即:
Column* pCol = ...
auto Applesauce = [&pCol]() -> void { cout << pCol->name(); };
Applesauce();
成为
Column* pCol = ...
auto Applesauce = [](Column*& pCol) -> void { cout << pCol->name(); };
Applesauce(pCol);
6.将lambda转换为函数
如果捕获到this
,请使用6A。如果未捕获this
,请使用6B。
6A。将此绑定的lambda转换为成员函数
- 剪切lambda语句并将其粘贴到当前函数之外
- 删除
= [this]
- 复制签名行
- 添加
SomeClass::
- 将签名粘贴到私有节中的类声明中
- 编译
即:
auto SomeClass::Applesauce () const -> void {
// ...
};
6B。将非此Lambda转换为自由函数
- 剪切lambda语句并将其粘贴到当前函数上方
- 删除
= []
- 编译
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 代码在main()中运行,但在函数中出现错误
- 在VS代码中交叉编译Windows与Linux上的MinGW的SDL程序
- 编译包含字符串的代码时遇到问题
- 我在c++代码中生成了一个运行时#3异常
- 如何在linux终端中同时编译和运行c++代码
- 为cl.exe(Visual Studio代码)指定命令行C++版本
- 在Linux for Windows上编译C++代码时出错
- 我的字符计数代码计算错误.为什么
- 孤立代码块在结构中引发异常
- 在编译C++代码(具有dlib和opencv)到WASM时面临问题
- 为什么我的C#代码在调用回C++COM直到Task时会暂停.等待/线程.加入
- 处理小于cpu数据总线的数据类型.(c++转换为机器代码)
- 此代码是否违反一个定义规则
- 为什么我的代码在输出中增加了93天
- 我的简单if-else语句是如何无法访问的代码
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 为什么在这个代码结束循环中没有得到结束
- 在c代码之间共享数据的最佳方式
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值