重构构造函数以使用初始化列表
Refactor constructor to use initialization list
我正在处理一个非常大的代码库(超过3M loc),我们显然有很多类,但它们中的大多数在构造函数中不使用初始化列表,而是在构造函数体中赋值(有些代码是很久以前编写的,所以这已经成为事实上的标准)。也许这些被编译器优化掉了,但我不确定真的是这样。
我正在尝试推广使用初始化列表,但是有一个大的代码库需要更新,所以有什么工具可以自动为我做这件事吗?把它指向一个类,找到所有的m_var = 0;
行并将它们移动到初始化列表(如果需要的话创建它)。
以及转换体内初始化到初始化列表,是否有一种方法来找出成员变量初始化在正确的顺序(即相同的顺序,因为他们在类的头文件中定义?我希望CppCheck会捡起这个,但它似乎没有。
大家好,我是一个cppcheck开发人员。
Cppcheck也有一个不匹配顺序的检查。但这是一个不确定的检查。
例如:class Fred {
public:
Fred() : y(0), x(0) {}
int x;
int y;
};
Cppcheck输出:
daniel@debian:~/cppcheck$ ./cppcheck --enable=style --inconclusive 1.cpp
Checking 1.cpp ...
[1.cpp:3] -> [1.cpp:4]: (style, inconclusive) Member variable 'Fred::x' is in the wrong place in the initializer list.
我们的简单检查将在订单不匹配时发出警告。这就是为什么它是不确定的。在上面的代码中,初始化顺序实际上并不重要——因为上面代码中的所有成员都是整型,所有初始化式都是常量字面值。
对于OP代码库的规模,需要的是一个程序转换系统(PTS)。这是一种工具,它将目标语言源文件解析为编译器数据结构(通常是ast),允许您对ast应用转换,然后可以重新生成有效的源代码,包括修改后程序的原始注释。把pst看作是在大型中进行重构的工具。
一个好的PTS将允许您编写源到源的转换的形式:
when you see *this*, replace it by *that* if *condition*
其中this和that用目标语言语法表示,其中this仅在源代码与显式语法匹配时才匹配。[这些不是字符串匹配;它们在ast上工作,所以布局不会影响它们匹配的能力。
你需要一个像这样的关键规则:
rule move_to_initializer(constructor_name:IDENTIFIER,
arguments: argument_list,
initializer_list: initializer,
member_name:IDENTIFIER,
initializer_expression: expression,
statements: statement_list
): constructor -> constructor =
" constructor_name(arguments): initializer_list
{ member_name = initializer_expression ;
statements } "
-> " constructor_name(arguments): initializer_list, member_name(initializer_expression)
{ statements } ";
这里解释了DMS软件再工程工具包的这些规则/模式的语法。DMS是我所知道的唯一一个可以处理c++的源码到源码的PTS;它甚至可以处理MSVS方言]。
我省略了一个可能必要的"if 条件"检查成员名是否确实是类的成员,假设您的构造函数没有滥用。
因为你的构造函数可能没有任何初始化列表,你需要一个辅助规则在必要时引入一个:
rule move_to_initializer(constructor_name:IDENTIFIER,
arguments: argument_list,
member_name:IDENTIFIER,
initializer_expression: expression,
statements: statement_list
): constructor -> constructor =
" constructor_name(arguments)
{ member_name = initializer_expression ;
statements } "
-> " constructor_name(arguments): member_name(initializer_expression)
{ statements } ";
{ member_name = e ; } "
你总是需要额外的规则来涵盖其他特殊情况,但它不应该超过几个。
关于检查初始化顺序,您可以使用(DMS)模式触发这样的检查:
pattern check_initializer_order(constructor_name:IDENTIFIER,
initializer_list: initializer,
statements: statement_list
): constructor =
" constructor_name(): initializer_list,
{ statements } "
if complain_if_not_ordered(constructor_name,initializer_list);
需要一个辅助的元谓词来检查它们的顺序,如果它们排列错了就会发出警告。您需要constructor_name来使谓词能够查找相应的类并检查成员的顺序。[DMS提供了使用该信息访问符号表的方法]。
或者,您可以使用不同的重写规则简单地重新排序它们:
rule order_initializers(constructor_name:IDENTIFIER,
arguments: argument_list,
initializer_list_prefix: initializer,
initializer_list_suffix: initializer,
member1_name:IDENTIFIER,
initializer1_expression: expression,
member2_name:IDENTIFIER,
initializer2_expression:expression,
statements: statement_list
): constructor -> constructor =
" constructor_name(arguments):
initializer_list_prefix,
member1_name(initializer1),
member2_name(initializer2),
initialize_list_suffix
{ statements } "
->
" constructor_name(arguments):
initializer_list_prefix,
member2_name(initializer2),
member1_name(initializer1),
initialize_list_suffix
{ statements } "
if is_wrong_order(constructor_name,member1_name,member2_name);
该规则本质上是对初始化式进行排序。[注意,这是冒泡排序:但初始化列表往往不会很长,而且无论如何你只会对每个构造函数运行一次。]
- C++类 - 初始化列表 - 递归 - 按值传递
- 在初始化列表之外手动调用基类的构造函数
- C++:带有大括号初始化列表的函数调用表达式 - 标准是否规定在单个元素列表的微不足道的情况下忽略大括号?
- std::map与谓词与初始化列表
- 类内初始化与构造函数初始化列表的顺序
- 当返回语句时,逗号运算符、大括号初始化列表和 std::unique_ptr 组合在一起
- 使用初始化列表填充C++中的多维结构数组时出现问题
- 如何在初始化列表中的构造函数之后初始化变量/对象?
- C++初始化列表与分配值
- C++初始化列表中的向量集大小或调整大小
- 在构造函数初始化列表中使用 std::variant
- emplace_back初始化列表错误,当初始化列表在独立变量上工作时
- 解释了构造函数成员初始化列表
- 使用初始化列表时如何获取私有数据?
- 用初始化列表和超类构造函数声明子类构造函数的正确方式
- 如何在成员初始化列表中声明共享指针
- 庞大的初始化列表,如何修复"fatal error C1060: compiler is out of heap space"
- 我可以检查初始化列表中设置的构造函数主体中的变量吗
- 使用整数初始化列表初始化长双精度的向量
- 是否可以在C++中使用初始化列表设置数组的特定成员?